From c35ec012b46dc76a5294f5cbf7227ce47e859e1d Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 08:55:17 +0100 Subject: [PATCH 1/8] Run prettier on spec/ folder --- spec/application-delegate-spec.js | 13 +- spec/async-spec-helpers.js | 5 +- spec/atom-environment-spec.js | 309 +- spec/atom-paths-spec.js | 19 +- spec/auto-update-manager-spec.js | 12 +- spec/command-installer-spec.js | 78 +- spec/command-registry-spec.js | 699 +-- spec/config-file-spec.js | 46 +- spec/config-spec.js | 1107 +++-- spec/dock-spec.js | 163 +- spec/git-repository-provider-spec.js | 27 +- spec/git-repository-spec.js | 122 +- spec/grammar-registry-spec.js | 471 +- spec/gutter-container-spec.js | 32 +- spec/gutter-spec.js | 16 +- spec/helpers/random.js | 2 +- spec/history-manager-spec.js | 103 +- spec/jasmine-list-reporter.js | 2 +- spec/main-process/atom-application.test.js | 613 ++- .../file-recovery-service.test.js | 72 +- spec/main-process/mocha-test-runner.js | 5 +- spec/main-process/parse-command-line.test.js | 19 +- spec/menu-sort-helpers-spec.js | 11 +- spec/native-watcher-registry-spec.js | 103 +- spec/notification-manager-spec.js | 15 +- spec/notification-spec.js | 17 +- spec/package-manager-spec.js | 786 +++- spec/package-transpilation-registry-spec.js | 176 +- spec/pane-container-spec.js | 171 +- spec/pane-spec.js | 448 +- spec/panel-container-element-spec.js | 90 +- spec/panel-container-spec.js | 74 +- spec/panel-spec.js | 22 +- spec/path-watcher-spec.js | 41 +- spec/project-spec.js | 502 ++- spec/reopen-project-menu-manager-spec.js | 156 +- spec/selection-spec.js | 51 +- spec/state-store-spec.js | 54 +- spec/style-manager-spec.js | 100 +- spec/syntax-scope-map-spec.js | 4 +- spec/text-editor-component-spec.js | 3801 ++++++++++++----- spec/text-editor-element-spec.js | 99 +- spec/text-editor-registry-spec.js | 117 +- spec/text-editor-spec.js | 2740 ++++++++---- spec/text-mate-language-mode-spec.js | 700 ++- spec/text-utils-spec.js | 50 +- spec/theme-manager-spec.js | 282 +- spec/title-bar-spec.js | 20 +- spec/tooltip-manager-spec.js | 167 +- spec/tree-sitter-language-mode-spec.js | 1417 +++--- spec/update-process-env-spec.js | 153 +- spec/uri-handler-registry-spec.js | 29 +- spec/view-registry-spec.js | 48 +- spec/window-event-handler-spec.js | 128 +- spec/workspace-center-spec.js | 24 +- spec/workspace-element-spec.js | 433 +- spec/workspace-spec.js | 1273 ++++-- 57 files changed, 12629 insertions(+), 5608 deletions(-) diff --git a/spec/application-delegate-spec.js b/spec/application-delegate-spec.js index 5512c88ea..97326aa24 100644 --- a/spec/application-delegate-spec.js +++ b/spec/application-delegate-spec.js @@ -1,14 +1,21 @@ /** @babel */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} 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() diff --git a/spec/async-spec-helpers.js b/spec/async-spec-helpers.js index 90cb85e23..c6a5920a5 100644 --- a/spec/async-spec-helpers.js +++ b/spec/async-spec-helpers.js @@ -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) { diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index 5e9617374..8e5dd5dba 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -1,4 +1,11 @@ -const {it, fit, ffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + beforeEach, + afterEach, + conditionPromise +} = require('./async-spec-helpers') const _ = require('underscore-plus') const fs = require('fs') const path = require('path') @@ -15,26 +22,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 }) }) }) }) @@ -122,7 +129,7 @@ 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 @@ -165,22 +172,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 +204,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 +219,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 +230,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 +240,9 @@ describe('AtomEnvironment', () => { const idleCallbacks = [] atomEnv.initialize({ window: { - requestIdleCallback (callback) { idleCallbacks.push(callback) }, + requestIdleCallback (callback) { + idleCallbacks.push(callback) + }, addEventListener () {}, removeEventListener () {} }, @@ -244,16 +255,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 +276,9 @@ describe('AtomEnvironment', () => { const idleCallbacks = [] atomEnv.initialize({ window: { - requestIdleCallback (callback) { idleCallbacks.push(callback) }, + requestIdleCallback (callback) { + idleCallbacks.push(callback) + }, addEventListener () {}, removeEventListener () {} }, @@ -278,7 +291,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 +307,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 +324,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 +352,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 +369,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 +387,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 +426,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') }) @@ -425,7 +457,9 @@ describe('AtomEnvironment', () => { it('adds the selected folder to the project', async () => { const initialPaths = 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 +471,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 +482,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 +520,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 +530,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 +547,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 +580,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 +596,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 +615,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 +636,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() @@ -591,9 +664,13 @@ describe('AtomEnvironment', () => { 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() @@ -607,16 +684,20 @@ describe('AtomEnvironment', () => { beforeEach(() => { let resolve = null - const promise = new Promise((r) => { resolve = r }) + const promise = new Promise(r => { + resolve = r + }) envLoaded = () => { resolve() 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 +731,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 +766,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 +776,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 +787,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 +815,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 +827,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 +839,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 +861,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 +892,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 +900,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]) }) }) diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index f4bbbf2b7..438154d72 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -1,14 +1,25 @@ /** @babel */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' -import {app} from 'remote' +import { + it, + fit, + ffit, + fffit, + 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')) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index ab9e0ed70..563085934 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -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' diff --git a/spec/command-installer-spec.js b/spec/command-installer-spec.js index b303d4954..2afa715fe 100644 --- a/spec/command-installer-spec.js +++ b/spec/command-installer-spec.js @@ -1,7 +1,14 @@ 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, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const CommandInstaller = require('../src/command-installer') describe('CommandInstaller on #darwin', () => { @@ -12,14 +19,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 +50,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 +63,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 +79,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 +107,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 +126,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 +152,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 +169,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 +193,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 +210,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() }) }) diff --git a/spec/command-registry-spec.js b/spec/command-registry-spec.js index 03ef0cc34..285cec055 100644 --- a/spec/command-registry-spec.js +++ b/spec/command-registry-spec.js @@ -1,289 +1,314 @@ -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, + fit, + ffit, + fffit, + 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 +316,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 +328,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() + })) +}) diff --git a/spec/config-file-spec.js b/spec/config-file-spec.js index ae5e05fe6..a053c9755 100644 --- a/spec/config-file-spec.js +++ b/spec/config-file-spec.js @@ -1,4 +1,11 @@ -const {it, fit, ffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + beforeEach, + afterEach, + conditionPromise +} = require('./async-spec-helpers') const fs = require('fs-plus') const path = require('path') const temp = require('temp').track() @@ -42,22 +49,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 +79,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 +133,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) } diff --git a/spec/config-spec.js b/spec/config-spec.js index 53cf9fffc..f942d62a5 100644 --- a/spec/config-spec.js +++ b/spec/config-spec.js @@ -19,121 +19,193 @@ describe('Config', () => { }) it("returns a deep clone of the key path's value", () => { - atom.config.set('value', {array: [1, {b: 2}, 3]}) + atom.config.set('value', { array: [1, { b: 2 }, 3] }) const retrievedValue = atom.config.get('value') retrievedValue.array[0] = 4 retrievedValue.array[1].b = 2.1 - expect(atom.config.get('value')).toEqual({array: [1, {b: 2}, 3]}) + expect(atom.config.get('value')).toEqual({ array: [1, { b: 2 }, 3] }) }) it('merges defaults into the returned value if both the assigned value and the default value are objects', () => { - atom.config.setDefaults('foo.bar', {baz: 1, ok: 2}) - atom.config.set('foo.bar', {baz: 3}) - expect(atom.config.get('foo.bar')).toEqual({baz: 3, ok: 2}) + atom.config.setDefaults('foo.bar', { baz: 1, ok: 2 }) + atom.config.set('foo.bar', { baz: 3 }) + expect(atom.config.get('foo.bar')).toEqual({ baz: 3, ok: 2 }) - atom.config.setDefaults('other', {baz: 1}) + atom.config.setDefaults('other', { baz: 1 }) atom.config.set('other', 7) expect(atom.config.get('other')).toBe(7) - atom.config.set('bar.baz', {a: 3}) - atom.config.setDefaults('bar', {baz: 7}) - expect(atom.config.get('bar.baz')).toEqual({a: 3}) + atom.config.set('bar.baz', { a: 3 }) + atom.config.setDefaults('bar', { baz: 7 }) + expect(atom.config.get('bar.baz')).toEqual({ a: 3 }) }) describe("when a 'sources' option is specified", () => it('only retrieves values from the specified sources', () => { - atom.config.set('x.y', 1, {scopeSelector: '.foo', source: 'a'}) - atom.config.set('x.y', 2, {scopeSelector: '.foo', source: 'b'}) - atom.config.set('x.y', 3, {scopeSelector: '.foo', source: 'c'}) - atom.config.setSchema('x.y', {type: 'integer', default: 4}) + atom.config.set('x.y', 1, { scopeSelector: '.foo', source: 'a' }) + atom.config.set('x.y', 2, { scopeSelector: '.foo', source: 'b' }) + atom.config.set('x.y', 3, { scopeSelector: '.foo', source: 'c' }) + atom.config.setSchema('x.y', { type: 'integer', default: 4 }) - expect(atom.config.get('x.y', {sources: ['a'], scope: ['.foo']})).toBe(1) - expect(atom.config.get('x.y', {sources: ['b'], scope: ['.foo']})).toBe(2) - expect(atom.config.get('x.y', {sources: ['c'], scope: ['.foo']})).toBe(3) + expect( + atom.config.get('x.y', { sources: ['a'], scope: ['.foo'] }) + ).toBe(1) + expect( + atom.config.get('x.y', { sources: ['b'], scope: ['.foo'] }) + ).toBe(2) + expect( + atom.config.get('x.y', { sources: ['c'], scope: ['.foo'] }) + ).toBe(3) // Schema defaults never match a specific source. We could potentially add a special "schema" source. - expect(atom.config.get('x.y', {sources: ['x'], scope: ['.foo']})).toBeUndefined() + expect( + atom.config.get('x.y', { sources: ['x'], scope: ['.foo'] }) + ).toBeUndefined() - expect(atom.config.get(null, {sources: ['a'], scope: ['.foo']}).x.y).toBe(1) - }) - ) + expect( + atom.config.get(null, { sources: ['a'], scope: ['.foo'] }).x.y + ).toBe(1) + })) describe("when an 'excludeSources' option is specified", () => it('only retrieves values from the specified sources', () => { atom.config.set('x.y', 0) - atom.config.set('x.y', 1, {scopeSelector: '.foo', source: 'a'}) - atom.config.set('x.y', 2, {scopeSelector: '.foo', source: 'b'}) - atom.config.set('x.y', 3, {scopeSelector: '.foo', source: 'c'}) - atom.config.setSchema('x.y', {type: 'integer', default: 4}) + atom.config.set('x.y', 1, { scopeSelector: '.foo', source: 'a' }) + atom.config.set('x.y', 2, { scopeSelector: '.foo', source: 'b' }) + atom.config.set('x.y', 3, { scopeSelector: '.foo', source: 'c' }) + atom.config.setSchema('x.y', { type: 'integer', default: 4 }) - expect(atom.config.get('x.y', {excludeSources: ['a'], scope: ['.foo']})).toBe(3) - expect(atom.config.get('x.y', {excludeSources: ['c'], scope: ['.foo']})).toBe(2) - expect(atom.config.get('x.y', {excludeSources: ['b', 'c'], scope: ['.foo']})).toBe(1) - expect(atom.config.get('x.y', {excludeSources: ['b', 'c', 'a'], scope: ['.foo']})).toBe(0) - expect(atom.config.get('x.y', {excludeSources: ['b', 'c', 'a', atom.config.getUserConfigPath()], scope: ['.foo']})).toBe(4) - expect(atom.config.get('x.y', {excludeSources: [atom.config.getUserConfigPath()]})).toBe(4) - }) - ) + expect( + atom.config.get('x.y', { excludeSources: ['a'], scope: ['.foo'] }) + ).toBe(3) + expect( + atom.config.get('x.y', { excludeSources: ['c'], scope: ['.foo'] }) + ).toBe(2) + expect( + atom.config.get('x.y', { + excludeSources: ['b', 'c'], + scope: ['.foo'] + }) + ).toBe(1) + expect( + atom.config.get('x.y', { + excludeSources: ['b', 'c', 'a'], + scope: ['.foo'] + }) + ).toBe(0) + expect( + atom.config.get('x.y', { + excludeSources: ['b', 'c', 'a', atom.config.getUserConfigPath()], + scope: ['.foo'] + }) + ).toBe(4) + expect( + atom.config.get('x.y', { + excludeSources: [atom.config.getUserConfigPath()] + }) + ).toBe(4) + })) describe("when a 'scope' option is given", () => { it('returns the property with the most specific scope selector', () => { - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.double.coffee'}) - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source .string.quoted.double'}) - atom.config.set('foo.bar.baz', 11, {scopeSelector: '.source'}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.double.coffee' + }) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source .string.quoted.double' + }) + atom.config.set('foo.bar.baz', 11, { scopeSelector: '.source' }) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']})).toBe(42) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.js', '.string.quoted.double.js']})).toBe(22) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.js', '.variable.assignment.js']})).toBe(11) - expect(atom.config.get('foo.bar.baz', {scope: ['.text']})).toBeUndefined() + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.double.coffee'] + }) + ).toBe(42) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.js', '.string.quoted.double.js'] + }) + ).toBe(22) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.js', '.variable.assignment.js'] + }) + ).toBe(11) + expect( + atom.config.get('foo.bar.baz', { scope: ['.text'] }) + ).toBeUndefined() }) it('favors the most recently added properties in the event of a specificity tie', () => { - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.single'}) - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source.coffee .string.quoted.double'}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.single' + }) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source.coffee .string.quoted.double' + }) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.single']})).toBe(42) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.single.double']})).toBe(22) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.single'] + }) + ).toBe(42) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.single.double'] + }) + ).toBe(22) }) describe('when there are global defaults', () => it('falls back to the global when there is no scoped property specified', () => { - atom.config.setDefaults('foo', {hasDefault: 'ok'}) - expect(atom.config.get('foo.hasDefault', {scope: ['.source.coffee', '.string.quoted.single']})).toBe('ok') - }) - ) + atom.config.setDefaults('foo', { hasDefault: 'ok' }) + expect( + atom.config.get('foo.hasDefault', { + scope: ['.source.coffee', '.string.quoted.single'] + }) + ).toBe('ok') + })) describe('when package settings are added after user settings', () => it("returns the user's setting because the user's setting has higher priority", () => { - atom.config.set('foo.bar.baz', 100, {scopeSelector: '.source.coffee'}) - atom.config.set('foo.bar.baz', 1, {scopeSelector: '.source.coffee', source: 'some-package'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(100) - }) - ) + atom.config.set('foo.bar.baz', 100, { + scopeSelector: '.source.coffee' + }) + atom.config.set('foo.bar.baz', 1, { + scopeSelector: '.source.coffee', + source: 'some-package' + }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(100) + })) }) }) describe('.getAll(keyPath, {scope, sources, excludeSources})', () => { it('reads all of the values for a given key-path', () => { expect(atom.config.set('foo', 41)).toBe(true) - expect(atom.config.set('foo', 43, {scopeSelector: '.a .b'})).toBe(true) - expect(atom.config.set('foo', 42, {scopeSelector: '.a'})).toBe(true) - expect(atom.config.set('foo', 44, {scopeSelector: '.a .b.c'})).toBe(true) + expect(atom.config.set('foo', 43, { scopeSelector: '.a .b' })).toBe(true) + expect(atom.config.set('foo', 42, { scopeSelector: '.a' })).toBe(true) + expect(atom.config.set('foo', 44, { scopeSelector: '.a .b.c' })).toBe( + true + ) - expect(atom.config.set('foo', -44, {scopeSelector: '.d'})).toBe(true) + expect(atom.config.set('foo', -44, { scopeSelector: '.d' })).toBe(true) - expect(atom.config.getAll('foo', {scope: ['.a', '.b.c']})).toEqual([ - {scopeSelector: '.a .b.c', value: 44}, - {scopeSelector: '.a .b', value: 43}, - {scopeSelector: '.a', value: 42}, - {scopeSelector: '*', value: 41} + expect(atom.config.getAll('foo', { scope: ['.a', '.b.c'] })).toEqual([ + { scopeSelector: '.a .b.c', value: 44 }, + { scopeSelector: '.a .b', value: 43 }, + { scopeSelector: '.a', value: 42 }, + { scopeSelector: '*', value: 41 } ]) }) it("includes the schema's default value", () => { - atom.config.setSchema('foo', {type: 'number', default: 40}) - expect(atom.config.set('foo', 43, {scopeSelector: '.a .b'})).toBe(true) - expect(atom.config.getAll('foo', {scope: ['.a', '.b.c']})).toEqual([ - {scopeSelector: '.a .b', value: 43}, - {scopeSelector: '*', value: 40} + atom.config.setSchema('foo', { type: 'number', default: 40 }) + expect(atom.config.set('foo', 43, { scopeSelector: '.a .b' })).toBe(true) + expect(atom.config.getAll('foo', { scope: ['.a', '.b.c'] })).toEqual([ + { scopeSelector: '.a .b', value: 43 }, + { scopeSelector: '*', value: 40 } ]) }) }) @@ -155,23 +227,33 @@ describe('Config', () => { }) it("does not save when a non-default 'source' is given", () => { - atom.config.set('foo.bar.baz', 42, {source: 'some-other-source', scopeSelector: '.a'}) + atom.config.set('foo.bar.baz', 42, { + source: 'some-other-source', + scopeSelector: '.a' + }) advanceClock(500) expect(savedSettings.length).toBe(0) }) it("does not allow a 'source' option without a 'scopeSelector'", () => { - expect(() => atom.config.set('foo', 1, {source: ['.source.ruby']})).toThrow() + expect(() => + atom.config.set('foo', 1, { source: ['.source.ruby'] }) + ).toThrow() }) describe('when the key-path is null', () => it('sets the root object', () => { - expect(atom.config.set(null, {editor: {tabLength: 6}})).toBe(true) + expect(atom.config.set(null, { editor: { tabLength: 6 } })).toBe(true) expect(atom.config.get('editor.tabLength')).toBe(6) - expect(atom.config.set(null, {editor: {tabLength: 8, scopeSelector: ['.source.js']}})).toBe(true) - expect(atom.config.get('editor.tabLength', {scope: ['.source.js']})).toBe(8) - }) - ) + expect( + atom.config.set(null, { + editor: { tabLength: 8, scopeSelector: ['.source.js'] } + }) + ).toBe(true) + expect( + atom.config.get('editor.tabLength', { scope: ['.source.js'] }) + ).toBe(8) + })) describe('when the value equals the default value', () => it("does not store the value in the user's config", () => { @@ -192,7 +274,7 @@ describe('Config', () => { }, sameObject: { type: 'object', - default: {a: 1, b: 2} + default: { a: 1, b: 2 } }, null: { type: '*', @@ -203,8 +285,7 @@ describe('Config', () => { default: undefined } } - } - ) + }) expect(atom.config.settings.foo).toBeUndefined() atom.config.set('foo.same', 1) @@ -212,32 +293,52 @@ describe('Config', () => { atom.config.set('foo.sameArray', [1, 2, 3]) atom.config.set('foo.null', undefined) atom.config.set('foo.undefined', null) - atom.config.set('foo.sameObject', {b: 2, a: 1}) + atom.config.set('foo.sameObject', { b: 2, a: 1 }) const userConfigPath = atom.config.getUserConfigPath() - expect(atom.config.get('foo.same', {sources: [userConfigPath]})).toBeUndefined() + expect( + atom.config.get('foo.same', { sources: [userConfigPath] }) + ).toBeUndefined() expect(atom.config.get('foo.changes')).toBe(2) - expect(atom.config.get('foo.changes', {sources: [userConfigPath]})).toBe(2) + expect( + atom.config.get('foo.changes', { sources: [userConfigPath] }) + ).toBe(2) atom.config.set('foo.changes', 1) - expect(atom.config.get('foo.changes', {sources: [userConfigPath]})).toBeUndefined() - }) - ) + expect( + atom.config.get('foo.changes', { sources: [userConfigPath] }) + ).toBeUndefined() + })) describe("when a 'scopeSelector' is given", () => it('sets the value and overrides the others', () => { - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.double.coffee'}) - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source .string.quoted.double'}) - atom.config.set('foo.bar.baz', 11, {scopeSelector: '.source'}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.double.coffee' + }) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source .string.quoted.double' + }) + atom.config.set('foo.bar.baz', 11, { scopeSelector: '.source' }) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']})).toBe(42) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.double.coffee'] + }) + ).toBe(42) - expect(atom.config.set('foo.bar.baz', 100, {scopeSelector: '.source.coffee .string.quoted.double.coffee'})).toBe(true) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']})).toBe(100) - }) - ) + expect( + atom.config.set('foo.bar.baz', 100, { + scopeSelector: '.source.coffee .string.quoted.double.coffee' + }) + ).toBe(true) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.double.coffee'] + }) + ).toBe(100) + })) }) describe('.unset(keyPath, {source, scopeSelector})', () => { @@ -263,12 +364,11 @@ describe('Config', () => { default: 0 } } - } - ) + }) ) it('sets the value of the key path to its default', () => { - atom.config.setDefaults('a', {b: 3}) + atom.config.setDefaults('a', { b: 3 }) atom.config.set('a.b', 4) expect(atom.config.get('a.b')).toBe(4) atom.config.unset('a.b') @@ -281,7 +381,7 @@ describe('Config', () => { }) it('calls ::save()', () => { - atom.config.setDefaults('a', {b: 3}) + atom.config.setDefaults('a', { b: 3 }) atom.config.set('a.b', 4) savedSettings.length = 0 @@ -293,125 +393,204 @@ describe('Config', () => { describe("when no 'scopeSelector' is given", () => { describe("when a 'source' but no key-path is given", () => it('removes all scoped settings with the given source', () => { - atom.config.set('foo.bar.baz', 1, {scopeSelector: '.a', source: 'source-a'}) - atom.config.set('foo.bar.quux', 2, {scopeSelector: '.b', source: 'source-a'}) - expect(atom.config.get('foo.bar', {scope: ['.a.b']})).toEqual({baz: 1, quux: 2}) + atom.config.set('foo.bar.baz', 1, { + scopeSelector: '.a', + source: 'source-a' + }) + atom.config.set('foo.bar.quux', 2, { + scopeSelector: '.b', + source: 'source-a' + }) + expect(atom.config.get('foo.bar', { scope: ['.a.b'] })).toEqual({ + baz: 1, + quux: 2 + }) - atom.config.unset(null, {source: 'source-a'}) - expect(atom.config.get('foo.bar', {scope: ['.a']})).toEqual({baz: 0, ok: 0}) - }) - ) + atom.config.unset(null, { source: 'source-a' }) + expect(atom.config.get('foo.bar', { scope: ['.a'] })).toEqual({ + baz: 0, + ok: 0 + }) + })) describe("when a 'source' and a key-path is given", () => it('removes all scoped settings with the given source and key-path', () => { atom.config.set('foo.bar.baz', 1) - atom.config.set('foo.bar.baz', 2, {scopeSelector: '.a', source: 'source-a'}) - atom.config.set('foo.bar.baz', 3, {scopeSelector: '.a.b', source: 'source-b'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.a.b']})).toEqual(3) + atom.config.set('foo.bar.baz', 2, { + scopeSelector: '.a', + source: 'source-a' + }) + atom.config.set('foo.bar.baz', 3, { + scopeSelector: '.a.b', + source: 'source-b' + }) + expect(atom.config.get('foo.bar.baz', { scope: ['.a.b'] })).toEqual(3) - atom.config.unset('foo.bar.baz', {source: 'source-b'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.a.b']})).toEqual(2) + atom.config.unset('foo.bar.baz', { source: 'source-b' }) + expect(atom.config.get('foo.bar.baz', { scope: ['.a.b'] })).toEqual(2) expect(atom.config.get('foo.bar.baz')).toEqual(1) - }) - ) + })) describe("when no 'source' is given", () => it('removes all scoped and unscoped properties for that key-path', () => { - atom.config.setDefaults('foo.bar', {baz: 100}) + atom.config.setDefaults('foo.bar', { baz: 100 }) - atom.config.set('foo.bar', {baz: 1, ok: 2}, {scopeSelector: '.a'}) - atom.config.set('foo.bar', {baz: 11, ok: 12}, {scopeSelector: '.b'}) - atom.config.set('foo.bar', {baz: 21, ok: 22}) + atom.config.set('foo.bar', { baz: 1, ok: 2 }, { scopeSelector: '.a' }) + atom.config.set( + 'foo.bar', + { baz: 11, ok: 12 }, + { scopeSelector: '.b' } + ) + atom.config.set('foo.bar', { baz: 21, ok: 22 }) atom.config.unset('foo.bar.baz') - expect(atom.config.get('foo.bar.baz', {scope: ['.a']})).toBe(100) - expect(atom.config.get('foo.bar.baz', {scope: ['.b']})).toBe(100) + expect(atom.config.get('foo.bar.baz', { scope: ['.a'] })).toBe(100) + expect(atom.config.get('foo.bar.baz', { scope: ['.b'] })).toBe(100) expect(atom.config.get('foo.bar.baz')).toBe(100) - expect(atom.config.get('foo.bar.ok', {scope: ['.a']})).toBe(2) - expect(atom.config.get('foo.bar.ok', {scope: ['.b']})).toBe(12) + expect(atom.config.get('foo.bar.ok', { scope: ['.a'] })).toBe(2) + expect(atom.config.get('foo.bar.ok', { scope: ['.b'] })).toBe(12) expect(atom.config.get('foo.bar.ok')).toBe(22) - }) - ) + })) }) describe("when a 'scopeSelector' is given", () => { it('restores the global default when no scoped default set', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(55) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.set('foo.bar.baz', 55, { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(55) - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(10) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(10) }) it('restores the scoped default when a scoped default is set', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee', source: 'some-source'}) - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee'}) - atom.config.set('foo.bar.ok', 100, {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(55) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee', + source: 'some-source' + }) + atom.config.set('foo.bar.baz', 55, { scopeSelector: '.source.coffee' }) + atom.config.set('foo.bar.ok', 100, { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(55) - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(42) - expect(atom.config.get('foo.bar.ok', {scope: ['.source.coffee']})).toBe(100) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(42) + expect( + atom.config.get('foo.bar.ok', { scope: ['.source.coffee'] }) + ).toBe(100) }) it('calls ::save()', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee'}) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.set('foo.bar.baz', 55, { scopeSelector: '.source.coffee' }) savedSettings.length = 0 - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) advanceClock(150) expect(savedSettings.length).toBe(1) }) it('allows removing settings for a specific source and scope selector', () => { - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee', source: 'source-a'}) - atom.config.set('foo.bar.baz', 65, {scopeSelector: '.source.coffee', source: 'source-b'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(65) + atom.config.set('foo.bar.baz', 55, { + scopeSelector: '.source.coffee', + source: 'source-a' + }) + atom.config.set('foo.bar.baz', 65, { + scopeSelector: '.source.coffee', + source: 'source-b' + }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(65) - atom.config.unset('foo.bar.baz', {source: 'source-b', scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string']})).toBe(55) + atom.config.unset('foo.bar.baz', { + source: 'source-b', + scopeSelector: '.source.coffee' + }) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string'] + }) + ).toBe(55) }) it('allows removing all settings for a specific source', () => { - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee', source: 'source-a'}) - atom.config.set('foo.bar.baz', 65, {scopeSelector: '.source.coffee', source: 'source-b'}) - atom.config.set('foo.bar.ok', 65, {scopeSelector: '.source.coffee', source: 'source-b'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(65) + atom.config.set('foo.bar.baz', 55, { + scopeSelector: '.source.coffee', + source: 'source-a' + }) + atom.config.set('foo.bar.baz', 65, { + scopeSelector: '.source.coffee', + source: 'source-b' + }) + atom.config.set('foo.bar.ok', 65, { + scopeSelector: '.source.coffee', + source: 'source-b' + }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(65) - atom.config.unset(null, {source: 'source-b', scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string']})).toBe(55) - expect(atom.config.get('foo.bar.ok', {scope: ['.source.coffee', '.string']})).toBe(0) + atom.config.unset(null, { + source: 'source-b', + scopeSelector: '.source.coffee' + }) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string'] + }) + ).toBe(55) + expect( + atom.config.get('foo.bar.ok', { + scope: ['.source.coffee', '.string'] + }) + ).toBe(0) }) it('does not call ::save or add a scoped property when no value has been set', () => { // see https://github.com/atom/atom/issues/4175 - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(10) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(10) expect(savedSettings.length).toBe(0) - const scopedProperties = atom.config.scopedSettingsStore.propertiesForSource('user-config') + const scopedProperties = atom.config.scopedSettingsStore.propertiesForSource( + 'user-config' + ) expect(scopedProperties['.coffee.source']).toBeUndefined() }) it('removes the scoped value when it was the only set value on the object', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee'}) - atom.config.set('foo.bar.ok', 20, {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(55) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.set('foo.bar.baz', 55, { scopeSelector: '.source.coffee' }) + atom.config.set('foo.bar.ok', 20, { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(55) advanceClock(150) savedSettings.length = 0 - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(10) - expect(atom.config.get('foo.bar.ok', {scope: ['.source.coffee']})).toBe(20) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(10) + expect( + atom.config.get('foo.bar.ok', { scope: ['.source.coffee'] }) + ).toBe(20) advanceClock(150) expect(savedSettings[0]['.coffee.source']).toEqual({ @@ -422,7 +601,7 @@ describe('Config', () => { } }) - atom.config.unset('foo.bar.ok', {scopeSelector: '.source.coffee'}) + atom.config.unset('foo.bar.ok', { scopeSelector: '.source.coffee' }) advanceClock(150) expect(savedSettings.length).toBe(2) @@ -430,15 +609,17 @@ describe('Config', () => { }) it('does not call ::save when the value is already at the default', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) atom.config.set('foo.bar.baz', 55) advanceClock(150) savedSettings.length = 0 - atom.config.unset('foo.bar.ok', {scopeSelector: '.source.coffee'}) + atom.config.unset('foo.bar.ok', { scopeSelector: '.source.coffee' }) advanceClock(150) expect(savedSettings.length).toBe(0) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(55) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(55) }) }) }) @@ -453,15 +634,24 @@ describe('Config', () => { atom.config.onDidChange('foo.bar.baz', observeHandler) }) - it('does not fire the given callback with the current value at the keypath', () => expect(observeHandler).not.toHaveBeenCalled()) + it('does not fire the given callback with the current value at the keypath', () => + expect(observeHandler).not.toHaveBeenCalled()) it('fires the callback every time the observed value changes', () => { atom.config.set('foo.bar.baz', 'value 2') - expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 2', oldValue: 'value 1'}) + expect(observeHandler).toHaveBeenCalledWith({ + newValue: 'value 2', + oldValue: 'value 1' + }) observeHandler.reset() - observeHandler.andCallFake(() => { throw new Error('oops') }) + observeHandler.andCallFake(() => { + throw new Error('oops') + }) expect(() => atom.config.set('foo.bar.baz', 'value 1')).toThrow('oops') - expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 1', oldValue: 'value 2'}) + expect(observeHandler).toHaveBeenCalledWith({ + newValue: 'value 1', + oldValue: 'value 2' + }) observeHandler.reset() // Regression: exception in earlier handler shouldn't put observer @@ -478,59 +668,93 @@ describe('Config', () => { atom.config.onDidChange(observeHandler) }) - it('does not fire the given callback initially', () => expect(observeHandler).not.toHaveBeenCalled()) + it('does not fire the given callback initially', () => + expect(observeHandler).not.toHaveBeenCalled()) it('fires the callback every time any value changes', () => { observeHandler.reset() // clear the initial call atom.config.set('foo.bar.baz', 'value 2') expect(observeHandler).toHaveBeenCalled() - expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe('value 2') - expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe('value 1') + expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe( + 'value 2' + ) + expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe( + 'value 1' + ) observeHandler.reset() atom.config.set('foo.bar.baz', 'value 1') expect(observeHandler).toHaveBeenCalled() - expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe('value 1') - expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe('value 2') + expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe( + 'value 1' + ) + expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe( + 'value 2' + ) observeHandler.reset() atom.config.set('foo.bar.int', 1) expect(observeHandler).toHaveBeenCalled() - expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.int).toBe(1) - expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.int).toBe(undefined) + expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.int).toBe( + 1 + ) + expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.int).toBe( + undefined + ) }) }) describe("when a 'scope' is given", () => it('calls the supplied callback when the value at the descriptor/keypath changes', () => { const changeSpy = jasmine.createSpy('onDidChange callback') - atom.config.onDidChange('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']}, changeSpy) + atom.config.onDidChange( + 'foo.bar.baz', + { scope: ['.source.coffee', '.string.quoted.double.coffee'] }, + changeSpy + ) atom.config.set('foo.bar.baz', 12) - expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12}) + expect(changeSpy).toHaveBeenCalledWith({ + oldValue: undefined, + newValue: 12 + }) changeSpy.reset() - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source .string.quoted.double', source: 'a'}) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: 22}) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source .string.quoted.double', + source: 'a' + }) + expect(changeSpy).toHaveBeenCalledWith({ oldValue: 12, newValue: 22 }) changeSpy.reset() - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.double.coffee', source: 'b'}) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 42}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.double.coffee', + source: 'b' + }) + expect(changeSpy).toHaveBeenCalledWith({ oldValue: 22, newValue: 42 }) changeSpy.reset() - atom.config.unset(null, {scopeSelector: '.source.coffee .string.quoted.double.coffee', source: 'b'}) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 42, newValue: 22}) + atom.config.unset(null, { + scopeSelector: '.source.coffee .string.quoted.double.coffee', + source: 'b' + }) + expect(changeSpy).toHaveBeenCalledWith({ oldValue: 42, newValue: 22 }) changeSpy.reset() - atom.config.unset(null, {scopeSelector: '.source .string.quoted.double', source: 'a'}) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 12}) + atom.config.unset(null, { + scopeSelector: '.source .string.quoted.double', + source: 'a' + }) + expect(changeSpy).toHaveBeenCalledWith({ oldValue: 22, newValue: 12 }) changeSpy.reset() atom.config.set('foo.bar.baz', undefined) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: undefined}) + expect(changeSpy).toHaveBeenCalledWith({ + oldValue: 12, + newValue: undefined + }) changeSpy.reset() - }) - ) + })) }) describe('.observe(keyPath, {scope})', () => { @@ -542,7 +766,8 @@ describe('Config', () => { observeSubscription = atom.config.observe('foo.bar.baz', observeHandler) }) - it('fires the given callback with the current value at the keypath', () => expect(observeHandler).toHaveBeenCalledWith('value 1')) + it('fires the given callback with the current value at the keypath', () => + expect(observeHandler).toHaveBeenCalledWith('value 1')) it('fires the callback every time the observed value changes', () => { observeHandler.reset() // clear the initial call @@ -555,7 +780,7 @@ describe('Config', () => { advanceClock(100) // complete pending save that was requested in ::set observeHandler.reset() - atom.config.resetUserSettings({foo: {}}) + atom.config.resetUserSettings({ foo: {} }) expect(observeHandler).toHaveBeenCalledWith(undefined) }) @@ -600,17 +825,29 @@ describe('Config', () => { }) it('allows settings to be observed in a specific scope', () => { - atom.config.observe('foo.bar.baz', {scope: ['.some.scope']}, observeHandler) - atom.config.observe('foo.bar.baz', {scope: ['.another.scope']}, otherHandler) + atom.config.observe( + 'foo.bar.baz', + { scope: ['.some.scope'] }, + observeHandler + ) + atom.config.observe( + 'foo.bar.baz', + { scope: ['.another.scope'] }, + otherHandler + ) - atom.config.set('foo.bar.baz', 'value 2', {scopeSelector: '.some'}) + atom.config.set('foo.bar.baz', 'value 2', { scopeSelector: '.some' }) expect(observeHandler).toHaveBeenCalledWith('value 2') expect(otherHandler).not.toHaveBeenCalledWith('value 2') }) it('calls the callback when properties with more specific selectors are removed', () => { const changeSpy = jasmine.createSpy() - atom.config.observe('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']}, changeSpy) + atom.config.observe( + 'foo.bar.baz', + { scope: ['.source.coffee', '.string.quoted.double.coffee'] }, + changeSpy + ) expect(changeSpy).toHaveBeenCalledWith('value 1') changeSpy.reset() @@ -618,19 +855,31 @@ describe('Config', () => { expect(changeSpy).toHaveBeenCalledWith(12) changeSpy.reset() - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source .string.quoted.double', source: 'a'}) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source .string.quoted.double', + source: 'a' + }) expect(changeSpy).toHaveBeenCalledWith(22) changeSpy.reset() - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.double.coffee', source: 'b'}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.double.coffee', + source: 'b' + }) expect(changeSpy).toHaveBeenCalledWith(42) changeSpy.reset() - atom.config.unset(null, {scopeSelector: '.source.coffee .string.quoted.double.coffee', source: 'b'}) + atom.config.unset(null, { + scopeSelector: '.source.coffee .string.quoted.double.coffee', + source: 'b' + }) expect(changeSpy).toHaveBeenCalledWith(22) changeSpy.reset() - atom.config.unset(null, {scopeSelector: '.source .string.quoted.double', source: 'a'}) + atom.config.unset(null, { + scopeSelector: '.source .string.quoted.double', + source: 'a' + }) expect(changeSpy).toHaveBeenCalledWith(12) changeSpy.reset() @@ -657,7 +906,10 @@ describe('Config', () => { }) expect(changeSpy.callCount).toBe(1) - expect(changeSpy.argsForCall[0][0]).toEqual({newValue: 3, oldValue: undefined}) + expect(changeSpy.argsForCall[0][0]).toEqual({ + newValue: 3, + oldValue: undefined + }) }) it('does not emit an event if no changes occur while paused', () => { @@ -683,14 +935,19 @@ describe('Config', () => { return Promise.resolve('a result') }) - waitsForPromise(() => transactionPromise.then(result => { - promiseResult = result - })) + waitsForPromise(() => + transactionPromise.then(result => { + promiseResult = result + }) + ) runs(() => { expect(promiseResult).toBe('a result') expect(changeSpy.callCount).toBe(1) - expect(changeSpy.argsForCall[0][0]).toEqual({newValue: 3, oldValue: undefined}) + expect(changeSpy.argsForCall[0][0]).toEqual({ + newValue: 3, + oldValue: undefined + }) }) }) @@ -703,14 +960,19 @@ describe('Config', () => { return Promise.reject(new Error('an error')) }) - waitsForPromise(() => transactionPromise.catch(error => { - promiseError = error - })) + waitsForPromise(() => + transactionPromise.catch(error => { + promiseError = error + }) + ) runs(() => { expect(promiseError.message).toBe('an error') expect(changeSpy.callCount).toBe(1) - expect(changeSpy.argsForCall[0][0]).toEqual({newValue: 3, oldValue: undefined}) + expect(changeSpy.argsForCall[0][0]).toEqual({ + newValue: 3, + oldValue: undefined + }) }) }) @@ -724,14 +986,19 @@ describe('Config', () => { throw error }) - waitsForPromise(() => transactionPromise.catch(e => { - promiseError = e - })) + waitsForPromise(() => + transactionPromise.catch(e => { + promiseError = e + }) + ) runs(() => { expect(promiseError).toBe(error) expect(changeSpy.callCount).toBe(1) - expect(changeSpy.argsForCall[0][0]).toEqual({newValue: 3, oldValue: undefined}) + expect(changeSpy.argsForCall[0][0]).toEqual({ + newValue: 3, + oldValue: undefined + }) }) }) }) @@ -740,10 +1007,10 @@ describe('Config', () => { it("returns an array of all of the config's source names", () => { expect(atom.config.getSources()).toEqual([]) - atom.config.set('a.b', 1, {scopeSelector: '.x1', source: 'source-1'}) - atom.config.set('a.c', 1, {scopeSelector: '.x1', source: 'source-1'}) - atom.config.set('a.b', 2, {scopeSelector: '.x2', source: 'source-2'}) - atom.config.set('a.b', 1, {scopeSelector: '.x3', source: 'source-3'}) + atom.config.set('a.b', 1, { scopeSelector: '.x1', source: 'source-1' }) + atom.config.set('a.c', 1, { scopeSelector: '.x1', source: 'source-1' }) + atom.config.set('a.b', 2, { scopeSelector: '.x2', source: 'source-2' }) + atom.config.set('a.b', 1, { scopeSelector: '.x3', source: 'source-3' }) expect(atom.config.getSources()).toEqual([ 'source-1', @@ -758,10 +1025,10 @@ describe('Config', () => { atom.config.set('a.b.c', 1) atom.config.set('a.b.d', 2) atom.config.set('x.y.z', 3) - atom.config.setDefaults('a.b', {e: 4, f: 5}) + atom.config.setDefaults('a.b', { e: 4, f: 5 }) atom.config.save() - expect(savedSettings).toEqual([{'*': atom.config.settings}]) + expect(savedSettings).toEqual([{ '*': atom.config.settings }]) }) it('serializes properties in alphabetical order', () => { @@ -774,12 +1041,12 @@ describe('Config', () => { atom.config.save() const writtenConfig = savedSettings[0] - expect(writtenConfig).toEqual({'*': atom.config.settings}) + expect(writtenConfig).toEqual({ '*': atom.config.settings }) let expectedKeys = ['bar', 'baz', 'foo'] let foundKeys = [] for (const key in writtenConfig['*']) { - if ((expectedKeys).includes(key)) { + if (expectedKeys.includes(key)) { foundKeys.push(key) } } @@ -787,7 +1054,7 @@ describe('Config', () => { expectedKeys = ['bar', 'foo'] foundKeys = [] for (const key in writtenConfig['*']['baz']) { - if ((expectedKeys).includes(key)) { + if (expectedKeys.includes(key)) { foundKeys.push(key) } } @@ -796,17 +1063,18 @@ describe('Config', () => { describe('when scoped settings are defined', () => { it('serializes any explicitly set config settings', () => { - atom.config.set('foo.bar', 'ruby', {scopeSelector: '.source.ruby'}) - atom.config.set('foo.omg', 'wow', {scopeSelector: '.source.ruby'}) - atom.config.set('foo.bar', 'coffee', {scopeSelector: '.source.coffee'}) + atom.config.set('foo.bar', 'ruby', { scopeSelector: '.source.ruby' }) + atom.config.set('foo.omg', 'wow', { scopeSelector: '.source.ruby' }) + atom.config.set('foo.bar', 'coffee', { + scopeSelector: '.source.coffee' + }) savedSettings.length = 0 atom.config.save() const writtenConfig = savedSettings[0] expect(writtenConfig).toEqualJson({ - '*': - atom.config.settings, + '*': atom.config.settings, '.ruby.source': { foo: { bar: 'ruby', @@ -856,7 +1124,9 @@ describe('Config', () => { } }) expect(atom.config.get('foo.bar')).toBe('baz') - expect(atom.config.get('foo.bar', {scope: ['.source.ruby']})).toBe('more-specific') + expect(atom.config.get('foo.bar', { scope: ['.source.ruby'] })).toBe( + 'more-specific' + ) }) }) @@ -878,20 +1148,22 @@ describe('Config', () => { }) expect(atom.config.get('foo.int')).toBe(12) expect(atom.config.get('foo.bar')).toBe('omg') - expect(atom.config.get('foo.int', {scope: ['.source.ruby']})).toBe(12) - expect(atom.config.get('foo.bar', {scope: ['.source.ruby']})).toBe('scoped') + expect(atom.config.get('foo.int', { scope: ['.source.ruby'] })).toBe(12) + expect(atom.config.get('foo.bar', { scope: ['.source.ruby'] })).toBe( + 'scoped' + ) }) }) it('updates the config data based on the file contents', () => { - atom.config.resetUserSettings({foo: {bar: 'baz'}}) + atom.config.resetUserSettings({ foo: { bar: 'baz' } }) expect(atom.config.get('foo.bar')).toBe('baz') }) it('notifies observers for updated keypaths on load', () => { const observeHandler = jasmine.createSpy('observeHandler') atom.config.observe('foo.bar', observeHandler) - atom.config.resetUserSettings({foo: {bar: 'baz'}}) + atom.config.resetUserSettings({ foo: { bar: 'baz' } }) expect(observeHandler).toHaveBeenCalledWith('baz') }) @@ -912,14 +1184,14 @@ describe('Config', () => { it('does not fire a change event for paths that did not change', () => { atom.config.resetUserSettings({ - foo: {bar: 'baz', int: 3} + foo: { bar: 'baz', int: 3 } }) const noChangeSpy = jasmine.createSpy('unchanged') - atom.config.onDidChange('foo.bar', (noChangeSpy)) + atom.config.onDidChange('foo.bar', noChangeSpy) atom.config.resetUserSettings({ - foo: {bar: 'baz', int: 4} + foo: { bar: 'baz', int: 4 } }) expect(noChangeSpy).not.toHaveBeenCalled() @@ -936,14 +1208,14 @@ describe('Config', () => { }) atom.config.resetUserSettings({ - foo: {bar: ['baz', 'quux'], int: 2} + foo: { bar: ['baz', 'quux'], int: 2 } }) const noChangeSpy = jasmine.createSpy('unchanged') - atom.config.onDidChange('foo.bar', (noChangeSpy)) + atom.config.onDidChange('foo.bar', noChangeSpy) atom.config.resetUserSettings({ - foo: {bar: ['baz', 'quux'], int: 2} + foo: { bar: ['baz', 'quux'], int: 2 } }) expect(noChangeSpy).not.toHaveBeenCalled() @@ -953,18 +1225,18 @@ describe('Config', () => { describe('when a setting with a default is removed', () => { it('resets the setting back to the default', () => { atom.config.resetUserSettings({ - foo: {bar: ['baz', 'quux'], int: 2} + foo: { bar: ['baz', 'quux'], int: 2 } }) const events = [] atom.config.onDidChange('foo.int', event => events.push(event)) atom.config.resetUserSettings({ - foo: {bar: ['baz', 'quux']} + foo: { bar: ['baz', 'quux'] } }) expect(events.length).toBe(1) - expect(events[0]).toEqual({oldValue: 2, newValue: 12}) + expect(events[0]).toEqual({ oldValue: 2, newValue: 12 }) }) }) }) @@ -978,7 +1250,9 @@ describe('Config', () => { expect(atom.config.pushAtKeyPath('foo.bar.baz', 'b')).toBe(2) expect(atom.config.get('foo.bar.baz')).toEqual(['a', 'b']) - expect(observeHandler).toHaveBeenCalledWith(atom.config.get('foo.bar.baz')) + expect(observeHandler).toHaveBeenCalledWith( + atom.config.get('foo.bar.baz') + ) }) }) @@ -991,7 +1265,9 @@ describe('Config', () => { expect(atom.config.unshiftAtKeyPath('foo.bar.baz', 'a')).toBe(2) expect(atom.config.get('foo.bar.baz')).toEqual(['a', 'b']) - expect(observeHandler).toHaveBeenCalledWith(atom.config.get('foo.bar.baz')) + expect(observeHandler).toHaveBeenCalledWith( + atom.config.get('foo.bar.baz') + ) }) }) @@ -1002,21 +1278,26 @@ describe('Config', () => { atom.config.observe('foo.bar.baz', observeHandler) observeHandler.reset() - expect(atom.config.removeAtKeyPath('foo.bar.baz', 'b')).toEqual(['a', 'c']) + expect(atom.config.removeAtKeyPath('foo.bar.baz', 'b')).toEqual([ + 'a', + 'c' + ]) expect(atom.config.get('foo.bar.baz')).toEqual(['a', 'c']) - expect(observeHandler).toHaveBeenCalledWith(atom.config.get('foo.bar.baz')) + expect(observeHandler).toHaveBeenCalledWith( + atom.config.get('foo.bar.baz') + ) }) }) describe('.setDefaults(keyPath, defaults)', () => { it('assigns any previously-unassigned keys to the object at the key path', () => { - atom.config.set('foo.bar.baz', {a: 1}) - atom.config.setDefaults('foo.bar.baz', {a: 2, b: 3, c: 4}) + atom.config.set('foo.bar.baz', { a: 1 }) + atom.config.setDefaults('foo.bar.baz', { a: 2, b: 3, c: 4 }) expect(atom.config.get('foo.bar.baz.a')).toBe(1) expect(atom.config.get('foo.bar.baz.b')).toBe(3) expect(atom.config.get('foo.bar.baz.c')).toBe(4) - atom.config.setDefaults('foo.quux', {x: 0, y: 1}) + atom.config.setDefaults('foo.quux', { x: 0, y: 1 }) expect(atom.config.get('foo.quux.x')).toBe(0) expect(atom.config.get('foo.quux.y')).toBe(1) }) @@ -1025,7 +1306,7 @@ describe('Config', () => { const updatedCallback = jasmine.createSpy('updated') atom.config.onDidChange('foo.bar.baz.a', updatedCallback) expect(updatedCallback.callCount).toBe(0) - atom.config.setDefaults('foo.bar.baz', {a: 2}) + atom.config.setDefaults('foo.bar.baz', { a: 2 }) expect(updatedCallback.callCount).toBe(1) }) }) @@ -1165,7 +1446,7 @@ describe('Config', () => { default: 12 }) - expect(atom.config.getSchema('foo.baz')).toEqual({type: 'any'}) + expect(atom.config.getSchema('foo.baz')).toEqual({ type: 'any' }) expect(atom.config.getSchema('foo.bar.anInt.baz')).toBe(null) }) @@ -1182,8 +1463,12 @@ describe('Config', () => { atom.config.setSchema('foo.bar.str', schema) expect(atom.config.get('foo.bar.str')).toBe('ok') - expect(atom.config.get('foo.bar.str', {scope: ['.source.js']})).toBe('omg') - expect(atom.config.get('foo.bar.str', {scope: ['.source.coffee']})).toBe('ok') + expect(atom.config.get('foo.bar.str', { scope: ['.source.js'] })).toBe( + 'omg' + ) + expect( + atom.config.get('foo.bar.str', { scope: ['.source.coffee'] }) + ).toBe('ok') }) describe('when a schema is added after config values have been set', () => { @@ -1206,47 +1491,93 @@ describe('Config', () => { it('respects the new schema when values are set', () => { expect(atom.config.set('foo.bar.str', 'global')).toBe(true) - expect(atom.config.set('foo.bar.str', 'scoped', {scopeSelector: '.source.js'})).toBe(true) + expect( + atom.config.set('foo.bar.str', 'scoped', { + scopeSelector: '.source.js' + }) + ).toBe(true) expect(atom.config.get('foo.bar.str')).toBe('global') - expect(atom.config.get('foo.bar.str', {scope: ['.source.js']})).toBe('scoped') + expect(atom.config.get('foo.bar.str', { scope: ['.source.js'] })).toBe( + 'scoped' + ) expect(atom.config.set('foo.bar.noschema', 'nsGlobal')).toBe(true) - expect(atom.config.set('foo.bar.noschema', 'nsScoped', {scopeSelector: '.source.js'})).toBe(true) + expect( + atom.config.set('foo.bar.noschema', 'nsScoped', { + scopeSelector: '.source.js' + }) + ).toBe(true) expect(atom.config.get('foo.bar.noschema')).toBe('nsGlobal') - expect(atom.config.get('foo.bar.noschema', {scope: ['.source.js']})).toBe('nsScoped') + expect( + atom.config.get('foo.bar.noschema', { scope: ['.source.js'] }) + ).toBe('nsScoped') expect(atom.config.set('foo.bar.int', 'nope')).toBe(true) - expect(atom.config.set('foo.bar.int', 'notanint', {scopeSelector: '.source.js'})).toBe(true) - expect(atom.config.set('foo.bar.int', 23, {scopeSelector: '.source.coffee'})).toBe(true) + expect( + atom.config.set('foo.bar.int', 'notanint', { + scopeSelector: '.source.js' + }) + ).toBe(true) + expect( + atom.config.set('foo.bar.int', 23, { + scopeSelector: '.source.coffee' + }) + ).toBe(true) expect(atom.config.get('foo.bar.int')).toBe('nope') - expect(atom.config.get('foo.bar.int', {scope: ['.source.js']})).toBe('notanint') - expect(atom.config.get('foo.bar.int', {scope: ['.source.coffee']})).toBe(23) + expect(atom.config.get('foo.bar.int', { scope: ['.source.js'] })).toBe( + 'notanint' + ) + expect( + atom.config.get('foo.bar.int', { scope: ['.source.coffee'] }) + ).toBe(23) atom.config.setSchema('foo.bar', schema) expect(atom.config.get('foo.bar.str')).toBe('global') - expect(atom.config.get('foo.bar.str', {scope: ['.source.js']})).toBe('scoped') + expect(atom.config.get('foo.bar.str', { scope: ['.source.js'] })).toBe( + 'scoped' + ) expect(atom.config.get('foo.bar.noschema')).toBe('nsGlobal') - expect(atom.config.get('foo.bar.noschema', {scope: ['.source.js']})).toBe('nsScoped') + expect( + atom.config.get('foo.bar.noschema', { scope: ['.source.js'] }) + ).toBe('nsScoped') expect(atom.config.get('foo.bar.int')).toBe(2) - expect(atom.config.get('foo.bar.int', {scope: ['.source.js']})).toBe(2) - expect(atom.config.get('foo.bar.int', {scope: ['.source.coffee']})).toBe(23) + expect(atom.config.get('foo.bar.int', { scope: ['.source.js'] })).toBe( + 2 + ) + expect( + atom.config.get('foo.bar.int', { scope: ['.source.coffee'] }) + ).toBe(23) }) it('sets all values that adhere to the schema', () => { expect(atom.config.set('foo.bar.int', 10)).toBe(true) - expect(atom.config.set('foo.bar.int', 15, {scopeSelector: '.source.js'})).toBe(true) - expect(atom.config.set('foo.bar.int', 23, {scopeSelector: '.source.coffee'})).toBe(true) + expect( + atom.config.set('foo.bar.int', 15, { scopeSelector: '.source.js' }) + ).toBe(true) + expect( + atom.config.set('foo.bar.int', 23, { + scopeSelector: '.source.coffee' + }) + ).toBe(true) expect(atom.config.get('foo.bar.int')).toBe(10) - expect(atom.config.get('foo.bar.int', {scope: ['.source.js']})).toBe(15) - expect(atom.config.get('foo.bar.int', {scope: ['.source.coffee']})).toBe(23) + expect(atom.config.get('foo.bar.int', { scope: ['.source.js'] })).toBe( + 15 + ) + expect( + atom.config.get('foo.bar.int', { scope: ['.source.coffee'] }) + ).toBe(23) atom.config.setSchema('foo.bar', schema) expect(atom.config.get('foo.bar.int')).toBe(10) - expect(atom.config.get('foo.bar.int', {scope: ['.source.js']})).toBe(15) - expect(atom.config.get('foo.bar.int', {scope: ['.source.coffee']})).toBe(23) + expect(atom.config.get('foo.bar.int', { scope: ['.source.js'] })).toBe( + 15 + ) + expect( + atom.config.get('foo.bar.int', { scope: ['.source.coffee'] }) + ).toBe(23) }) }) @@ -1449,7 +1780,7 @@ describe('Config', () => { expect(atom.config.set('foo.bar.aString', [])).toBe(false) expect(atom.config.get('foo.bar.aString')).toBe('ok') - expect(atom.config.set('foo.bar.aString', {nope: 'nope'})).toBe(false) + expect(atom.config.set('foo.bar.aString', { nope: 'nope' })).toBe(false) expect(atom.config.get('foo.bar.aString')).toBe('ok') }) @@ -1468,8 +1799,7 @@ describe('Config', () => { atom.config.setSchema('foo.bar.aString', schema) atom.config.set('foo.bar.aString', 'abcdefg') expect(atom.config.get('foo.bar.aString')).toBe('abc') - }) - ) + })) }) describe('when the value has an "object" type', () => { @@ -1501,8 +1831,7 @@ describe('Config', () => { nestedObject: { nestedBool: 'true' } - } - ) + }) expect(atom.config.get('foo.bar')).toEqual({ anInt: 23, nestedObject: { @@ -1512,13 +1841,14 @@ describe('Config', () => { }) it('will set only the values that adhere to the schema', () => { - expect(atom.config.set('foo.bar', { - anInt: 'nope', - nestedObject: { - nestedBool: true - } - } - )).toBe(true) + expect( + atom.config.set('foo.bar', { + anInt: 'nope', + nestedObject: { + nestedBool: true + } + }) + ).toBe(true) expect(atom.config.get('foo.bar.anInt')).toEqual(12) expect(atom.config.get('foo.bar.nestedObject.nestedBool')).toEqual(true) }) @@ -1534,17 +1864,19 @@ describe('Config', () => { } }, additionalProperties: false - } - ) + }) - expect(atom.config.set('foo.bar', {anInt: 5, somethingElse: 'ok'})).toBe(true) + expect( + atom.config.set('foo.bar', { anInt: 5, somethingElse: 'ok' }) + ).toBe(true) expect(atom.config.get('foo.bar.anInt')).toBe(5) expect(atom.config.get('foo.bar.somethingElse')).toBeUndefined() - expect(atom.config.set('foo.bar.somethingElse', {anInt: 5})).toBe(false) + expect(atom.config.set('foo.bar.somethingElse', { anInt: 5 })).toBe( + false + ) expect(atom.config.get('foo.bar.somethingElse')).toBeUndefined() - }) - ) + })) describe('when the value has an additionalProperties schema', () => it('validates properties of the object against that schema', () => { @@ -1559,21 +1891,23 @@ describe('Config', () => { additionalProperties: { type: 'string' } - } - ) + }) - expect(atom.config.set('foo.bar', {anInt: 5, somethingElse: 'ok'})).toBe(true) + expect( + atom.config.set('foo.bar', { anInt: 5, somethingElse: 'ok' }) + ).toBe(true) expect(atom.config.get('foo.bar.anInt')).toBe(5) expect(atom.config.get('foo.bar.somethingElse')).toBe('ok') expect(atom.config.set('foo.bar.somethingElse', 7)).toBe(false) expect(atom.config.get('foo.bar.somethingElse')).toBe('ok') - expect(atom.config.set('foo.bar', {anInt: 6, somethingElse: 7})).toBe(true) + expect( + atom.config.set('foo.bar', { anInt: 6, somethingElse: 7 }) + ).toBe(true) expect(atom.config.get('foo.bar.anInt')).toBe(6) expect(atom.config.get('foo.bar.somethingElse')).toBe(undefined) - }) - ) + })) }) describe('when the value has an "array" type', () => { @@ -1647,46 +1981,131 @@ describe('Config', () => { it('coerces various types to a color object', () => { atom.config.set('foo.bar.aColor', 'red') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 0, blue: 0, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 0, + blue: 0, + alpha: 1 + }) atom.config.set('foo.bar.aColor', '#020') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 0, green: 34, blue: 0, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 0, + green: 34, + blue: 0, + alpha: 1 + }) atom.config.set('foo.bar.aColor', '#abcdef') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 171, green: 205, blue: 239, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 171, + green: 205, + blue: 239, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 'rgb(1,2,3)') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 1, green: 2, blue: 3, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 1, + green: 2, + blue: 3, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 'rgba(4,5,6,.7)') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 4, green: 5, blue: 6, alpha: 0.7}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 4, + green: 5, + blue: 6, + alpha: 0.7 + }) atom.config.set('foo.bar.aColor', 'hsl(120,100%,50%)') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 0, green: 255, blue: 0, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 0, + green: 255, + blue: 0, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 'hsla(120,100%,50%,0.3)') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 0, green: 255, blue: 0, alpha: 0.3}) - atom.config.set('foo.bar.aColor', {red: 100, green: 255, blue: 2, alpha: 0.5}) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 100, green: 255, blue: 2, alpha: 0.5}) - atom.config.set('foo.bar.aColor', {red: 255}) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 0, blue: 0, alpha: 1}) - atom.config.set('foo.bar.aColor', {red: 1000}) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 0, blue: 0, alpha: 1}) - atom.config.set('foo.bar.aColor', {red: 'dark'}) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 0, green: 0, blue: 0, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 0, + green: 255, + blue: 0, + alpha: 0.3 + }) + atom.config.set('foo.bar.aColor', { + red: 100, + green: 255, + blue: 2, + alpha: 0.5 + }) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 100, + green: 255, + blue: 2, + alpha: 0.5 + }) + atom.config.set('foo.bar.aColor', { red: 255 }) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 0, + blue: 0, + alpha: 1 + }) + atom.config.set('foo.bar.aColor', { red: 1000 }) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 0, + blue: 0, + alpha: 1 + }) + atom.config.set('foo.bar.aColor', { red: 'dark' }) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 0, + green: 0, + blue: 0, + alpha: 1 + }) }) it('reverts back to the default value when undefined is passed to set', () => { atom.config.set('foo.bar.aColor', undefined) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) }) it('will not set non-colors', () => { atom.config.set('foo.bar.aColor', null) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 'nope') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 30) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) atom.config.set('foo.bar.aColor', false) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) }) it('returns a clone of the Color when returned in a parent object', () => { @@ -1726,9 +2145,9 @@ describe('Config', () => { type: 'string', default: 'one', enum: [ - {value: 'one', description: 'One'}, + { value: 'one', description: 'One' }, 'two', - {value: 'three', description: 'Three'} + { value: 'three', description: 'Three' } ] } } @@ -1821,54 +2240,78 @@ describe('Config', () => { const dummyPath = '/Users/dummy/path.json' describe('project settings', () => { it('returns a deep clone of the property value', () => { - atom.config.resetProjectSettings({'*': {'value': {array: [1, {b: 2}, 3]}}}, dummyPath) + atom.config.resetProjectSettings( + { '*': { value: { array: [1, { b: 2 }, 3] } } }, + dummyPath + ) const retrievedValue = atom.config.get('value') retrievedValue.array[0] = 4 retrievedValue.array[1].b = 2.1 - expect(atom.config.get('value')).toEqual({array: [1, {b: 2}, 3]}) + expect(atom.config.get('value')).toEqual({ array: [1, { b: 2 }, 3] }) }) it('properly gets project settings', () => { - atom.config.resetProjectSettings({'*': {'foo': 'wei'}}, dummyPath) + atom.config.resetProjectSettings({ '*': { foo: 'wei' } }, dummyPath) expect(atom.config.get('foo')).toBe('wei') - atom.config.resetProjectSettings({'*': {'foo': {'bar': 'baz'}}}, dummyPath) + atom.config.resetProjectSettings( + { '*': { foo: { bar: 'baz' } } }, + dummyPath + ) expect(atom.config.get('foo.bar')).toBe('baz') }) it('gets project settings with higher priority than regular settings', () => { atom.config.set('foo', 'bar') - atom.config.resetProjectSettings({'*': {'foo': 'baz'}}, dummyPath) + atom.config.resetProjectSettings({ '*': { foo: 'baz' } }, dummyPath) expect(atom.config.get('foo')).toBe('baz') }) it('correctly gets nested and scoped properties for project settings', () => { expect(atom.config.set('foo.bar.str', 'global')).toBe(true) - expect(atom.config.set('foo.bar.str', 'scoped', {scopeSelector: '.source.js'})).toBe(true) + expect( + atom.config.set('foo.bar.str', 'scoped', { + scopeSelector: '.source.js' + }) + ).toBe(true) expect(atom.config.get('foo.bar.str')).toBe('global') - expect(atom.config.get('foo.bar.str', {scope: ['.source.js']})).toBe('scoped') + expect( + atom.config.get('foo.bar.str', { scope: ['.source.js'] }) + ).toBe('scoped') }) it('returns a deep clone of the property value', () => { - atom.config.set('value', {array: [1, {b: 2}, 3]}) + atom.config.set('value', { array: [1, { b: 2 }, 3] }) const retrievedValue = atom.config.get('value') retrievedValue.array[0] = 4 retrievedValue.array[1].b = 2.1 - expect(atom.config.get('value')).toEqual({array: [1, {b: 2}, 3]}) + expect(atom.config.get('value')).toEqual({ array: [1, { b: 2 }, 3] }) }) it('gets scoped values correctly', () => { - atom.config.set('foo', 'bam', {scope: ['second']}) - expect(atom.config.get('foo', {'scopeSelector': 'second'})).toBe('bam') - atom.config.resetProjectSettings({'*': {'foo': 'baz'}, 'second': {'foo': 'bar'}}, dummyPath) - expect(atom.config.get('foo', {'scopeSelector': 'second'})).toBe('baz') + atom.config.set('foo', 'bam', { scope: ['second'] }) + expect(atom.config.get('foo', { scopeSelector: 'second' })).toBe( + 'bam' + ) + atom.config.resetProjectSettings( + { '*': { foo: 'baz' }, second: { foo: 'bar' } }, + dummyPath + ) + expect(atom.config.get('foo', { scopeSelector: 'second' })).toBe( + 'baz' + ) atom.config.clearProjectSettings() - expect(atom.config.get('foo', {'scopeSelector': 'second'})).toBe('bam') + expect(atom.config.get('foo', { scopeSelector: 'second' })).toBe( + 'bam' + ) }) it('clears project settings correctly', () => { atom.config.set('foo', 'bar') expect(atom.config.get('foo')).toBe('bar') - atom.config.resetProjectSettings({'*': {'foo': 'baz'}, 'second': {'foo': 'bar'}}, dummyPath) + atom.config.resetProjectSettings( + { '*': { foo: 'baz' }, second: { foo: 'bar' } }, + dummyPath + ) expect(atom.config.get('foo')).toBe('baz') expect(atom.config.getSources().length).toBe(1) atom.config.clearProjectSettings() @@ -1881,12 +2324,14 @@ describe('Config', () => { describe('config.getAll', () => { const dummyPath = '/Users/dummy/path.json' it('gets settings in the same way .get would return them', () => { - atom.config.resetProjectSettings({'*': {'a': 'b'}}, dummyPath) + atom.config.resetProjectSettings({ '*': { a: 'b' } }, dummyPath) atom.config.set('a', 'f') - expect(atom.config.getAll('a')).toEqual([{ - scopeSelector: '*', - value: 'b' - }]) + expect(atom.config.getAll('a')).toEqual([ + { + scopeSelector: '*', + value: 'b' + } + ]) }) }) }) diff --git a/spec/dock-spec.js b/spec/dock-spec.js index 4713347a8..6b97b6aa8 100644 --- a/spec/dock-spec.js +++ b/spec/dock-spec.js @@ -2,7 +2,14 @@ const Grim = require('grim') -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' import etch from 'etch' const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise @@ -16,7 +23,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 +48,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 +61,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 +90,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 +172,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 +241,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 +277,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 +316,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,9 +336,13 @@ 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({ name: 'DockTestItem', @@ -287,10 +352,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 +367,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 +393,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 +417,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() }) }) diff --git a/spec/git-repository-provider-spec.js b/spec/git-repository-provider-spec.js index 2e679e755..d70d7db3f 100644 --- a/spec/git-repository-provider-spec.js +++ b/spec/git-repository-provider-spec.js @@ -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, fit, ffit, fffit, 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) }) diff --git a/spec/git-repository-spec.js b/spec/git-repository-spec.js index 65548fb3b..60a0846ac 100644 --- a/spec/git-repository-spec.js +++ b/spec/git-repository-spec.js @@ -1,4 +1,11 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const path = require('path') const fs = require('fs-plus') const temp = require('temp').track() @@ -25,30 +32,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 +157,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 +174,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 +189,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 +211,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 +234,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 +256,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 +272,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 +292,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 +320,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 +332,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 +343,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 +358,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 +372,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 +388,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,7 +421,7 @@ 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] @@ -376,14 +433,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 } diff --git a/spec/grammar-registry-spec.js b/spec/grammar-registry-spec.js index b6b314ac3..2f7d82299 100644 --- a/spec/grammar-registry-spec.js +++ b/spec/grammar-registry-spec.js @@ -1,4 +1,11 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const dedent = require('dedent') const path = require('path') @@ -13,14 +20,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 +42,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 +54,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 +75,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 +99,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 +144,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 +159,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 +168,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 +190,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 +209,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 +270,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,7 +303,9 @@ 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) expect(retainedBufferCount(grammarRegistry)).toBe(1) @@ -238,19 +321,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 +347,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 +368,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 +391,20 @@ describe('GrammarRegistry', () => { await atom.packages.activatePackage('language-coffee-script') let fileContent = 'first-line\n' - expect(atom.grammars.selectGrammar('dummy.coffee', fileContent).name).toBe('CoffeeScript') + expect( + atom.grammars.selectGrammar('dummy.coffee', fileContent).name + ).toBe('CoffeeScript') fileContent = '' - expect(atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name).toBe('Null Grammar') + expect( + atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name + ).toBe('Null Grammar') - fileContent += '\n' - expect(atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name).toBe('Property List (XML)') + fileContent += + '\n' + 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 +413,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 +451,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 +481,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 +496,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 +549,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 +564,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 +578,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 typedef struct { void verb(); } Noun; - `) + ` + ) expect(grammar.name).toBe('C') - grammar = grammarRegistry.selectGrammar('test.h', dedent ` + grammar = grammarRegistry.selectGrammar( + 'test.h', + dedent` #include 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 +753,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 +783,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 +805,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 +825,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') }) diff --git a/spec/gutter-container-spec.js b/spec/gutter-container-spec.js index f41f1d220..50451ecfb 100644 --- a/spec/gutter-container-spec.js +++ b/spec/gutter-container-spec.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([]) - }) -) + })) }) diff --git a/spec/gutter-spec.js b/spec/gutter-spec.js index 4ae23db3e..c5051ea22 100644 --- a/spec/gutter-spec.js +++ b/spec/gutter-spec.js @@ -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() }) }) diff --git a/spec/helpers/random.js b/spec/helpers/random.js index 62f0e1920..3a2ff9159 100644 --- a/spec/helpers/random.js +++ b/spec/helpers/random.js @@ -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()) diff --git a/spec/history-manager-spec.js b/spec/history-manager-spec.js index cc2a20058..2d1a09cdc 100644 --- a/spec/history-manager-spec.js +++ b/spec/history-manager-spec.js @@ -1,10 +1,17 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') -const {Emitter, Disposable, CompositeDisposable} = require('event-kit') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') +const { Emitter, Disposable, CompositeDisposable } = require('event-kit') -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 +23,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 +50,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 +83,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 +110,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 +119,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 +129,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 +153,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 +162,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 +171,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 +180,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 +190,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 +203,7 @@ describe("HistoryManager", () => { }) }) - describe("saveState", () => { + describe('saveState', () => { let savedHistory beforeEach(() => { // historyManager.saveState is spied on globally to prevent specs from @@ -195,11 +218,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']) }) diff --git a/spec/jasmine-list-reporter.js b/spec/jasmine-list-reporter.js index b6976b6ca..ffe8b0858 100644 --- a/spec/jasmine-list-reporter.js +++ b/spec/jasmine-list-reporter.js @@ -1,4 +1,4 @@ -const {TerminalReporter} = require('jasmine-tagged') +const { TerminalReporter } = require('jasmine-tagged') class JasmineListReporter extends TerminalReporter { fullDescription (spec) { diff --git a/spec/main-process/atom-application.test.js b/spec/main-process/atom-application.test.js index 296ffcad9..83feac157 100644 --- a/spec/main-process/atom-application.test.js +++ b/spec/main-process/atom-application.test.js @@ -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 () { diff --git a/spec/main-process/file-recovery-service.test.js b/spec/main-process/file-recovery-service.test.js index 45c10c25b..25484f6c2 100644 --- a/spec/main-process/file-recovery-service.test.js +++ b/spec/main-process/file-recovery-service.test.js @@ -1,13 +1,13 @@ -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 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 +25,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 +117,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 +130,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 +154,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) }) }) diff --git a/spec/main-process/mocha-test-runner.js b/spec/main-process/mocha-test-runner.js index 61d533417..ef8ef69ef 100644 --- a/spec/main-process/mocha-test-runner.js +++ b/spec/main-process/mocha-test-runner.js @@ -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 = { diff --git a/spec/main-process/parse-command-line.test.js b/spec/main-process/parse-command-line.test.js index bb5d625a9..2fcece469 100644 --- a/spec/main-process/parse-command-line.test.js +++ b/spec/main-process/parse-command-line.test.js @@ -3,7 +3,14 @@ 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 +21,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) diff --git a/spec/menu-sort-helpers-spec.js b/spec/menu-sort-helpers-spec.js index 86f00b37e..0e63824ff 100644 --- a/spec/menu-sort-helpers-spec.js +++ b/spec/menu-sort-helpers-spec.js @@ -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' }, diff --git a/spec/native-watcher-registry-spec.js b/spec/native-watcher-registry-spec.js index bc657f496..c83028c73 100644 --- a/spec/native-watcher-registry-spec.js +++ b/spec/native-watcher-registry-spec.js @@ -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) }) }) }) diff --git a/spec/notification-manager-spec.js b/spec/notification-manager-spec.js index 3a8544d4e..3fd91d0ca 100644 --- a/spec/notification-manager-spec.js +++ b/spec/notification-manager-spec.js @@ -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') diff --git a/spec/notification-spec.js b/spec/notification-spec.js index 4702cd13d..179f70950 100644 --- a/spec/notification-spec.js +++ b/spec/notification-spec.js @@ -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) - }) - ) + })) }) }) diff --git a/spec/package-manager-spec.js b/spec/package-manager-spec.js index dd87f85fa..9dec5bde6 100644 --- a/spec/package-manager-spec.js +++ b/spec/package-manager-spec.js @@ -4,11 +4,11 @@ const Package = require('../src/package') const PackageManager = require('../src/package-manager') const temp = require('temp').track() const fs = require('fs-plus') -const {Disposable} = require('atom') -const {buildKeydownEvent} = require('../src/keymap-extensions') -const {mockLocalStorage} = require('./spec-helper') +const { Disposable } = require('atom') +const { buildKeydownEvent } = require('../src/keymap-extensions') +const { mockLocalStorage } = require('./spec-helper') const ModuleCache = require('../src/module-cache') -const {it, fit, ffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { it, fit, ffit, beforeEach, afterEach } = require('./async-spec-helpers') describe('PackageManager', () => { function createTestElement (className) { @@ -25,20 +25,28 @@ describe('PackageManager', () => { it('adds regular package path', () => { const packageManger = new PackageManager({}) const configDirPath = path.join('~', 'someConfig') - packageManger.initialize({configDirPath}) + packageManger.initialize({ configDirPath }) expect(packageManger.packageDirPaths.length).toBe(1) - expect(packageManger.packageDirPaths[0]).toBe(path.join(configDirPath, 'packages')) + expect(packageManger.packageDirPaths[0]).toBe( + path.join(configDirPath, 'packages') + ) }) it('adds regular package path, dev package path, and Atom repo package path in dev mode and dev resource path is set', () => { const packageManger = new PackageManager({}) const configDirPath = path.join('~', 'someConfig') const resourcePath = path.join('~', '/atom') - packageManger.initialize({configDirPath, resourcePath, devMode: true}) + packageManger.initialize({ configDirPath, resourcePath, devMode: true }) expect(packageManger.packageDirPaths.length).toBe(3) - expect(packageManger.packageDirPaths).toContain(path.join(configDirPath, 'packages')) - expect(packageManger.packageDirPaths).toContain(path.join(configDirPath, 'dev', 'packages')) - expect(packageManger.packageDirPaths).toContain(path.join(resourcePath, 'packages')) + expect(packageManger.packageDirPaths).toContain( + path.join(configDirPath, 'packages') + ) + expect(packageManger.packageDirPaths).toContain( + path.join(configDirPath, 'dev', 'packages') + ) + expect(packageManger.packageDirPaths).toContain( + path.join(resourcePath, 'packages') + ) }) }) @@ -102,43 +110,62 @@ describe('PackageManager', () => { atom.notifications.onDidAddNotification(addErrorHandler) expect(() => pack.reloadStylesheets()).not.toThrow() expect(addErrorHandler.callCount).toBe(2) - expect(addErrorHandler.argsForCall[1][0].message).toContain('Failed to reload the package-with-invalid-styles package stylesheets') - expect(addErrorHandler.argsForCall[1][0].options.packageName).toEqual('package-with-invalid-styles') + expect(addErrorHandler.argsForCall[1][0].message).toContain( + 'Failed to reload the package-with-invalid-styles package stylesheets' + ) + expect(addErrorHandler.argsForCall[1][0].options.packageName).toEqual( + 'package-with-invalid-styles' + ) }) it('returns null if the package has an invalid package.json', () => { spyOn(atom, 'inSpecMode').andReturn(false) const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - expect(atom.packages.loadPackage('package-with-broken-package-json')).toBeNull() + expect( + atom.packages.loadPackage('package-with-broken-package-json') + ).toBeNull() expect(addErrorHandler.callCount).toBe(1) - expect(addErrorHandler.argsForCall[0][0].message).toContain('Failed to load the package-with-broken-package-json package') - expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual('package-with-broken-package-json') + expect(addErrorHandler.argsForCall[0][0].message).toContain( + 'Failed to load the package-with-broken-package-json package' + ) + expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual( + 'package-with-broken-package-json' + ) }) it('returns null if the package name or path starts with a dot', () => { - expect(atom.packages.loadPackage('/Users/user/.atom/packages/.git')).toBeNull() + expect( + atom.packages.loadPackage('/Users/user/.atom/packages/.git') + ).toBeNull() }) it('normalizes short repository urls in package.json', () => { - let {metadata} = atom.packages.loadPackage('package-with-short-url-package-json') + let { metadata } = atom.packages.loadPackage( + 'package-with-short-url-package-json' + ) expect(metadata.repository.type).toBe('git') - expect(metadata.repository.url).toBe('https://github.com/example/repo'); - - ({metadata} = atom.packages.loadPackage('package-with-invalid-url-package-json')) + expect(metadata.repository.url).toBe('https://github.com/example/repo') + ;({ metadata } = atom.packages.loadPackage( + 'package-with-invalid-url-package-json' + )) expect(metadata.repository.type).toBe('git') expect(metadata.repository.url).toBe('foo') }) it('trims git+ from the beginning and .git from the end of repository URLs, even if npm already normalized them ', () => { - const {metadata} = atom.packages.loadPackage('package-with-prefixed-and-suffixed-repo-url') + const { metadata } = atom.packages.loadPackage( + 'package-with-prefixed-and-suffixed-repo-url' + ) expect(metadata.repository.type).toBe('git') expect(metadata.repository.url).toBe('https://github.com/example/repo') }) it('returns null if the package is not found in any package directory', () => { spyOn(console, 'warn') - expect(atom.packages.loadPackage('this-package-cannot-be-found')).toBeNull() + expect( + atom.packages.loadPackage('this-package-cannot-be-found') + ).toBeNull() expect(console.warn.callCount).toBe(1) expect(console.warn.argsForCall[0][0]).toContain('Could not resolve') }) @@ -146,11 +173,23 @@ describe('PackageManager', () => { describe('when the package is deprecated', () => { it('returns null', () => { spyOn(console, 'warn') - expect(atom.packages.loadPackage(path.join(__dirname, 'fixtures', 'packages', 'wordcount'))).toBeNull() - expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.9')).toBe(true) - expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.0')).toBe(true) - expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.1')).toBe(false) - expect(atom.packages.getDeprecatedPackageMetadata('wordcount').version).toBe('<=2.2.0') + expect( + atom.packages.loadPackage( + path.join(__dirname, 'fixtures', 'packages', 'wordcount') + ) + ).toBeNull() + expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.9')).toBe( + true + ) + expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.0')).toBe( + true + ) + expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.1')).toBe( + false + ) + expect( + atom.packages.getDeprecatedPackageMetadata('wordcount').version + ).toBe('<=2.2.0') }) }) @@ -169,13 +208,13 @@ describe('PackageManager', () => { it("registers any deserializers specified in the package's package.json", () => { atom.packages.loadPackage('package-with-deserializers') - const state1 = {deserializer: 'Deserializer1', a: 'b'} + const state1 = { deserializer: 'Deserializer1', a: 'b' } expect(atom.deserializers.deserialize(state1)).toEqual({ wasDeserializedBy: 'deserializeMethod1', state: state1 }) - const state2 = {deserializer: 'Deserializer2', c: 'd'} + const state2 = { deserializer: 'Deserializer2', c: 'd' } expect(atom.deserializers.deserialize(state2)).toEqual({ wasDeserializedBy: 'deserializeMethod2', state: state2 @@ -186,15 +225,21 @@ describe('PackageManager', () => { jasmine.useRealClock() const providers = [] - atom.packages.serviceHub.consume('atom.directory-provider', '^0.1.0', provider => providers.push(provider)) + atom.packages.serviceHub.consume( + 'atom.directory-provider', + '^0.1.0', + provider => providers.push(provider) + ) atom.packages.loadPackage('package-with-directory-provider') - expect(providers.map(p => p.name)).toEqual(['directory provider from package-with-directory-provider']) + expect(providers.map(p => p.name)).toEqual([ + 'directory provider from package-with-directory-provider' + ]) }) describe("when there are view providers specified in the package's package.json", () => { - const model1 = {worksWithViewProvider1: true} - const model2 = {worksWithViewProvider2: true} + const model1 = { worksWithViewProvider1: true } + const model2 = { worksWithViewProvider2: true } afterEach(async () => { await atom.packages.deactivatePackage('package-with-view-providers') @@ -254,8 +299,8 @@ describe('PackageManager', () => { expect(atom.config.getSchema('package-with-json-config-schema')).toEqual({ type: 'object', properties: { - a: {type: 'number', default: 5}, - b: {type: 'string', default: 'five'} + a: { type: 'number', default: 5 }, + b: { type: 'string', default: 'five' } } }) @@ -268,8 +313,8 @@ describe('PackageManager', () => { expect(atom.config.getSchema('package-with-json-config-schema')).toEqual({ type: 'object', properties: { - a: {type: 'number', default: 5}, - b: {type: 'string', default: 'five'} + a: { type: 'number', default: 5 }, + b: { type: 'string', default: 'five' } } }) }) @@ -288,12 +333,16 @@ describe('PackageManager', () => { }) it("does not defer loading the package's main module if the package previously used Atom APIs when its main module was required", () => { - const pack1 = atom.packages.loadPackage('package-with-eval-time-api-calls') + const pack1 = atom.packages.loadPackage( + 'package-with-eval-time-api-calls' + ) expect(pack1.mainModule).toBeDefined() atom.packages.unloadPackage('package-with-eval-time-api-calls') - const pack2 = atom.packages.loadPackage('package-with-eval-time-api-calls') + const pack2 = atom.packages.loadPackage( + 'package-with-eval-time-api-calls' + ) expect(pack2.mainModule).not.toBeNull() }) }) @@ -302,35 +351,49 @@ describe('PackageManager', () => { describe('::loadAvailablePackage(availablePackage)', () => { describe('if the package was preloaded', () => { it('adds the package path to the module cache', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) const metadata = atom.packages.loadPackageMetadata(availablePackage) - atom.packages.preloadPackage( - availablePackage.name, - { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), - metadata - } - ) + atom.packages.preloadPackage(availablePackage.name, { + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), + metadata + }) atom.packages.loadAvailablePackage(availablePackage) expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(true) - expect(ModuleCache.add).toHaveBeenCalledWith(availablePackage.path, metadata) + expect(ModuleCache.add).toHaveBeenCalledWith( + availablePackage.path, + metadata + ) }) it('deactivates it if it had been disabled', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) const metadata = atom.packages.loadPackageMetadata(availablePackage) const preloadedPackage = atom.packages.preloadPackage( availablePackage.name, { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), metadata } ) @@ -338,7 +401,10 @@ describe('PackageManager', () => { expect(preloadedPackage.settingsActivated).toBe(true) expect(preloadedPackage.menusActivated).toBe(true) - atom.packages.loadAvailablePackage(availablePackage, new Set([availablePackage.name])) + atom.packages.loadAvailablePackage( + availablePackage, + new Set([availablePackage.name]) + ) expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) expect(preloadedPackage.keymapActivated).toBe(false) expect(preloadedPackage.settingsActivated).toBe(false) @@ -346,16 +412,23 @@ describe('PackageManager', () => { }) it('deactivates it and reloads the new one if trying to load the same package outside of the bundle', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) const metadata = atom.packages.loadPackageMetadata(availablePackage) const preloadedPackage = atom.packages.preloadPackage( availablePackage.name, { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), metadata } ) @@ -374,21 +447,30 @@ describe('PackageManager', () => { describe('if the package was not preloaded', () => { it('adds the package path to the module cache', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true const metadata = atom.packages.loadPackageMetadata(availablePackage) atom.packages.loadAvailablePackage(availablePackage) - expect(ModuleCache.add).toHaveBeenCalledWith(availablePackage.path, metadata) + expect(ModuleCache.add).toHaveBeenCalledWith( + availablePackage.path, + metadata + ) }) }) }) describe('preloading', () => { it('requires the main module, loads the config schema and activates keymaps, menus and settings without reactivating them during package activation', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true const metadata = atom.packages.loadPackageMetadata(availablePackage) - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) atom.packages.packagesCache = {} @@ -399,7 +481,10 @@ describe('PackageManager', () => { const preloadedPackage = atom.packages.preloadPackage( availablePackage.name, { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), metadata } ) @@ -415,7 +500,9 @@ describe('PackageManager', () => { spyOn(atom.config, 'setSchema') atom.packages.loadAvailablePackage(availablePackage) - expect(preloadedPackage.getMainModulePath()).toBe(path.join(availablePackage.path, metadata.main)) + expect(preloadedPackage.getMainModulePath()).toBe( + path.join(availablePackage.path, metadata.main) + ) atom.packages.activatePackage(availablePackage.name) expect(atom.keymaps.add).not.toHaveBeenCalled() @@ -430,10 +517,14 @@ describe('PackageManager', () => { }) it('deactivates disabled keymaps during package activation', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true const metadata = atom.packages.loadPackageMetadata(availablePackage) - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) atom.packages.packagesCache = {} @@ -444,7 +535,10 @@ describe('PackageManager', () => { const preloadedPackage = atom.packages.preloadPackage( availablePackage.name, { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), metadata } ) @@ -453,7 +547,9 @@ describe('PackageManager', () => { expect(preloadedPackage.menusActivated).toBe(true) atom.packages.loadAvailablePackage(availablePackage) - atom.config.set('core.packagesWithKeymapsDisabled', [availablePackage.name]) + atom.config.set('core.packagesWithKeymapsDisabled', [ + availablePackage.name + ]) atom.packages.activatePackage(availablePackage.name) expect(preloadedPackage.keymapActivated).toBe(false) @@ -539,14 +635,26 @@ describe('PackageManager', () => { }) it('assigns config schema, including defaults when package contains a schema', async () => { - expect(atom.config.get('package-with-config-schema.numbers.one')).toBeUndefined() + expect( + atom.config.get('package-with-config-schema.numbers.one') + ).toBeUndefined() await atom.packages.activatePackage('package-with-config-schema') - expect(atom.config.get('package-with-config-schema.numbers.one')).toBe(1) - expect(atom.config.get('package-with-config-schema.numbers.two')).toBe(2) - expect(atom.config.set('package-with-config-schema.numbers.one', 'nope')).toBe(false) - expect(atom.config.set('package-with-config-schema.numbers.one', '10')).toBe(true) - expect(atom.config.get('package-with-config-schema.numbers.one')).toBe(10) + expect(atom.config.get('package-with-config-schema.numbers.one')).toBe( + 1 + ) + expect(atom.config.get('package-with-config-schema.numbers.two')).toBe( + 2 + ) + expect( + atom.config.set('package-with-config-schema.numbers.one', 'nope') + ).toBe(false) + expect( + atom.config.set('package-with-config-schema.numbers.one', '10') + ).toBe(true) + expect(atom.config.get('package-with-config-schema.numbers.one')).toBe( + 10 + ) }) describe('when the package metadata includes `activationCommands`', () => { @@ -559,10 +667,18 @@ describe('PackageManager', () => { spyOn(mainModule, 'activate').andCallThrough() spyOn(Package.prototype, 'requireMainModule').andCallThrough() - workspaceCommandListener = jasmine.createSpy('workspaceCommandListener') - registration = atom.commands.add('.workspace', 'activation-command', workspaceCommandListener) + workspaceCommandListener = jasmine.createSpy( + 'workspaceCommandListener' + ) + registration = atom.commands.add( + '.workspace', + 'activation-command', + workspaceCommandListener + ) - promise = atom.packages.activatePackage('package-with-activation-commands') + promise = atom.packages.activatePackage( + 'package-with-activation-commands' + ) }) afterEach(() => { @@ -575,7 +691,11 @@ describe('PackageManager', () => { it('defers requiring/activating the main module until an activation event bubbles to the root view', async () => { expect(Package.prototype.requireMainModule.callCount).toBe(0) - atom.workspace.getElement().dispatchEvent(new CustomEvent('activation-command', {bubbles: true})) + atom.workspace + .getElement() + .dispatchEvent( + new CustomEvent('activation-command', { bubbles: true }) + ) await promise expect(Package.prototype.requireMainModule.callCount).toBe(1) @@ -584,9 +704,17 @@ describe('PackageManager', () => { it('triggers the activation event on all handlers registered during activation', async () => { await atom.workspace.open() - const editorElement = atom.workspace.getActiveTextEditor().getElement() - const editorCommandListener = jasmine.createSpy('editorCommandListener') - atom.commands.add('atom-text-editor', 'activation-command', editorCommandListener) + const editorElement = atom.workspace + .getActiveTextEditor() + .getElement() + const editorCommandListener = jasmine.createSpy( + 'editorCommandListener' + ) + atom.commands.add( + 'atom-text-editor', + 'activation-command', + editorCommandListener + ) atom.commands.dispatch(editorElement, 'activation-command') expect(mainModule.activate.callCount).toBe(1) @@ -605,7 +733,9 @@ describe('PackageManager', () => { mainModule = require('./fixtures/packages/package-with-empty-activation-commands/index') spyOn(mainModule, 'activate').andCallThrough() - atom.packages.activatePackage('package-with-empty-activation-commands') + atom.packages.activatePackage( + 'package-with-empty-activation-commands' + ) expect(mainModule.activate.callCount).toBe(1) }) @@ -614,54 +744,80 @@ describe('PackageManager', () => { spyOn(atom, 'inSpecMode').andReturn(false) const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - expect(() => atom.packages.activatePackage('package-with-invalid-activation-commands')).not.toThrow() + expect(() => + atom.packages.activatePackage( + 'package-with-invalid-activation-commands' + ) + ).not.toThrow() expect(addErrorHandler.callCount).toBe(1) - expect(addErrorHandler.argsForCall[0][0].message).toContain('Failed to activate the package-with-invalid-activation-commands package') - expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual('package-with-invalid-activation-commands') + expect(addErrorHandler.argsForCall[0][0].message).toContain( + 'Failed to activate the package-with-invalid-activation-commands package' + ) + expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual( + 'package-with-invalid-activation-commands' + ) }) it('adds a notification when the context menu is invalid', () => { spyOn(atom, 'inSpecMode').andReturn(false) const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - expect(() => atom.packages.activatePackage('package-with-invalid-context-menu')).not.toThrow() + expect(() => + atom.packages.activatePackage('package-with-invalid-context-menu') + ).not.toThrow() expect(addErrorHandler.callCount).toBe(1) - expect(addErrorHandler.argsForCall[0][0].message).toContain('Failed to activate the package-with-invalid-context-menu package') - expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual('package-with-invalid-context-menu') + expect(addErrorHandler.argsForCall[0][0].message).toContain( + 'Failed to activate the package-with-invalid-context-menu package' + ) + expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual( + 'package-with-invalid-context-menu' + ) }) it('adds a notification when the grammar is invalid', async () => { let notificationEvent await new Promise(resolve => { - const subscription = atom.notifications.onDidAddNotification(event => { - notificationEvent = event - subscription.dispose() - resolve() - }) + const subscription = atom.notifications.onDidAddNotification( + event => { + notificationEvent = event + subscription.dispose() + resolve() + } + ) atom.packages.activatePackage('package-with-invalid-grammar') }) - expect(notificationEvent.message).toContain('Failed to load a package-with-invalid-grammar package grammar') - expect(notificationEvent.options.packageName).toEqual('package-with-invalid-grammar') + expect(notificationEvent.message).toContain( + 'Failed to load a package-with-invalid-grammar package grammar' + ) + expect(notificationEvent.options.packageName).toEqual( + 'package-with-invalid-grammar' + ) }) it('adds a notification when the settings are invalid', async () => { let notificationEvent await new Promise(resolve => { - const subscription = atom.notifications.onDidAddNotification(event => { - notificationEvent = event - subscription.dispose() - resolve() - }) + const subscription = atom.notifications.onDidAddNotification( + event => { + notificationEvent = event + subscription.dispose() + resolve() + } + ) atom.packages.activatePackage('package-with-invalid-settings') }) - expect(notificationEvent.message).toContain('Failed to load the package-with-invalid-settings package settings') - expect(notificationEvent.options.packageName).toEqual('package-with-invalid-settings') + expect(notificationEvent.message).toContain( + 'Failed to load the package-with-invalid-settings package settings' + ) + expect(notificationEvent.options.packageName).toEqual( + 'package-with-invalid-settings' + ) }) }) }) @@ -710,7 +866,9 @@ describe('PackageManager', () => { expect(Package.prototype.requireMainModule.callCount).toBe(0) - await atom.packages.activatePackage('package-with-empty-activation-hooks') + await atom.packages.activatePackage( + 'package-with-empty-activation-hooks' + ) expect(mainModule.activate.callCount).toBe(1) expect(Package.prototype.requireMainModule.callCount).toBe(1) }) @@ -729,7 +887,9 @@ describe('PackageManager', () => { it('does not throw an exception', () => { spyOn(console, 'error') spyOn(console, 'warn').andCallThrough() - expect(() => atom.packages.activatePackage('package-without-module')).not.toThrow() + expect(() => + atom.packages.activatePackage('package-without-module') + ).not.toThrow() expect(console.error).not.toHaveBeenCalled() expect(console.warn).not.toHaveBeenCalled() }) @@ -744,7 +904,9 @@ describe('PackageManager', () => { }) it("passes the activate method the package's previously serialized state if it exists", async () => { - const pack = await atom.packages.activatePackage('package-with-serialization') + const pack = await atom.packages.activatePackage( + 'package-with-serialization' + ) expect(pack.mainModule.someNumber).not.toBe(77) pack.mainModule.someNumber = 77 atom.packages.serializePackage('package-with-serialization') @@ -752,7 +914,7 @@ describe('PackageManager', () => { spyOn(pack.mainModule, 'activate').andCallThrough() await atom.packages.activatePackage('package-with-serialization') - expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77}) + expect(pack.mainModule.activate).toHaveBeenCalledWith({ someNumber: 77 }) }) it('invokes ::onDidActivatePackage listeners with the activated package', async () => { @@ -771,15 +933,23 @@ describe('PackageManager', () => { atom.config.set('core.disabledPackages', []) const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - expect(() => atom.packages.activatePackage('package-that-throws-an-exception')).not.toThrow() + expect(() => + atom.packages.activatePackage('package-that-throws-an-exception') + ).not.toThrow() expect(addErrorHandler.callCount).toBe(1) - expect(addErrorHandler.argsForCall[0][0].message).toContain('Failed to load the package-that-throws-an-exception package') - expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual('package-that-throws-an-exception') + expect(addErrorHandler.argsForCall[0][0].message).toContain( + 'Failed to load the package-that-throws-an-exception package' + ) + expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual( + 'package-that-throws-an-exception' + ) }) it('re-throws the exception in test mode', () => { atom.config.set('core.disabledPackages', []) - expect(() => atom.packages.activatePackage('package-that-throws-an-exception')).toThrow('This package throws an exception') + expect(() => + atom.packages.activatePackage('package-that-throws-an-exception') + ).toThrow('This package throws an exception') }) }) @@ -793,7 +963,9 @@ describe('PackageManager', () => { expect('Error to be thrown').toBe('') } catch (error) { expect(console.warn.callCount).toBe(1) - expect(error.message).toContain("Failed to load package 'this-doesnt-exist'") + expect(error.message).toContain( + "Failed to load package 'this-doesnt-exist'" + ) } }) }) @@ -804,14 +976,44 @@ describe('PackageManager', () => { const element1 = createTestElement('test-1') const element2 = createTestElement('test-2') const element3 = createTestElement('test-3') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element2})).toHaveLength(0) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element3})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element2 + }) + ).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element3 + }) + ).toHaveLength(0) await atom.packages.activatePackage('package-with-keymaps') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})[0].command).toBe('test-1') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element2})[0].command).toBe('test-2') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element3})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + })[0].command + ).toBe('test-1') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element2 + })[0].command + ).toBe('test-2') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element3 + }) + ).toHaveLength(0) }) }) @@ -819,30 +1021,64 @@ describe('PackageManager', () => { it('loads only the keymaps specified by the manifest, in the specified order', async () => { const element1 = createTestElement('test-1') const element3 = createTestElement('test-3') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) await atom.packages.activatePackage('package-with-keymaps-manifest') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})[0].command).toBe('keymap-1') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-n', target: element1})[0].command).toBe('keymap-2') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-y', target: element3})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + })[0].command + ).toBe('keymap-1') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-n', + target: element1 + })[0].command + ).toBe('keymap-2') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-y', + target: element3 + }) + ).toHaveLength(0) }) }) describe('when the keymap file is empty', () => { it('does not throw an error on activation', async () => { await atom.packages.activatePackage('package-with-empty-keymap') - expect(atom.packages.isPackageActive('package-with-empty-keymap')).toBe(true) + expect( + atom.packages.isPackageActive('package-with-empty-keymap') + ).toBe(true) }) }) describe("when the package's keymaps have been disabled", () => { it('does not add the keymaps', async () => { const element1 = createTestElement('test-1') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) - atom.config.set('core.packagesWithKeymapsDisabled', ['package-with-keymaps-manifest']) + atom.config.set('core.packagesWithKeymapsDisabled', [ + 'package-with-keymaps-manifest' + ]) await atom.packages.activatePackage('package-with-keymaps-manifest') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) }) }) @@ -850,8 +1086,14 @@ describe('PackageManager', () => { it("ignores package names in the array that aren't loaded", () => { atom.packages.observePackagesWithKeymapsDisabled() - expect(() => atom.config.set('core.packagesWithKeymapsDisabled', ['package-does-not-exist'])).not.toThrow() - expect(() => atom.config.set('core.packagesWithKeymapsDisabled', [])).not.toThrow() + expect(() => + atom.config.set('core.packagesWithKeymapsDisabled', [ + 'package-does-not-exist' + ]) + ).not.toThrow() + expect(() => + atom.config.set('core.packagesWithKeymapsDisabled', []) + ).not.toThrow() }) }) @@ -862,11 +1104,23 @@ describe('PackageManager', () => { await atom.packages.activatePackage('package-with-keymaps-manifest') - atom.config.set('core.packagesWithKeymapsDisabled', ['package-with-keymaps-manifest']) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) + atom.config.set('core.packagesWithKeymapsDisabled', [ + 'package-with-keymaps-manifest' + ]) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) atom.config.set('core.packagesWithKeymapsDisabled', []) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})[0].command).toBe('keymap-1') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + })[0].command + ).toBe('keymap-1') }) }) @@ -896,17 +1150,24 @@ describe('PackageManager', () => { }) it("doesn't override user-defined keymaps", async () => { - fs.writeFileSync(userKeymapPath, `".test-1": {"ctrl-z": "user-command"}`) + fs.writeFileSync( + userKeymapPath, + `".test-1": {"ctrl-z": "user-command"}` + ) atom.keymaps.loadUserKeymap() await atom.packages.activatePackage('package-with-keymaps') - atom.keymaps.handleKeyboardEvent(buildKeydownEvent('z', {ctrl: true, target: element})) + atom.keymaps.handleKeyboardEvent( + buildKeydownEvent('z', { ctrl: true, target: element }) + ) expect(events.length).toBe(1) expect(events[0].type).toBe('user-command') await atom.packages.deactivatePackage('package-with-keymaps') await atom.packages.activatePackage('package-with-keymaps') - atom.keymaps.handleKeyboardEvent(buildKeydownEvent('z', {ctrl: true, target: element})) + atom.keymaps.handleKeyboardEvent( + buildKeydownEvent('z', { ctrl: true, target: element }) + ) expect(events.length).toBe(2) expect(events[1].type).toBe('user-command') }) @@ -928,9 +1189,15 @@ describe('PackageManager', () => { expect(atom.menu.template.length).toBe(2) expect(atom.menu.template[0].label).toBe('Second to Last') expect(atom.menu.template[1].label).toBe('Last') - expect(atom.contextMenu.templateForElement(element)[0].label).toBe('Menu item 1') - expect(atom.contextMenu.templateForElement(element)[1].label).toBe('Menu item 2') - expect(atom.contextMenu.templateForElement(element)[2].label).toBe('Menu item 3') + expect(atom.contextMenu.templateForElement(element)[0].label).toBe( + 'Menu item 1' + ) + expect(atom.contextMenu.templateForElement(element)[1].label).toBe( + 'Menu item 2' + ) + expect(atom.contextMenu.templateForElement(element)[2].label).toBe( + 'Menu item 3' + ) }) }) @@ -942,16 +1209,24 @@ describe('PackageManager', () => { await atom.packages.activatePackage('package-with-menus-manifest') expect(atom.menu.template[0].label).toBe('Second to Last') expect(atom.menu.template[1].label).toBe('Last') - expect(atom.contextMenu.templateForElement(element)[0].label).toBe('Menu item 2') - expect(atom.contextMenu.templateForElement(element)[1].label).toBe('Menu item 1') - expect(atom.contextMenu.templateForElement(element)[2]).toBeUndefined() + expect(atom.contextMenu.templateForElement(element)[0].label).toBe( + 'Menu item 2' + ) + expect(atom.contextMenu.templateForElement(element)[1].label).toBe( + 'Menu item 1' + ) + expect( + atom.contextMenu.templateForElement(element)[2] + ).toBeUndefined() }) }) describe('when the menu file is empty', () => { it('does not throw an error on activation', async () => { await atom.packages.activatePackage('package-with-empty-menu') - expect(atom.packages.isPackageActive('package-with-empty-menu')).toBe(true) + expect(atom.packages.isPackageActive('package-with-empty-menu')).toBe( + true + ) }) }) }) @@ -959,28 +1234,47 @@ describe('PackageManager', () => { describe('stylesheet loading', () => { describe("when the metadata contains a 'styleSheets' manifest", () => { it('loads style sheets from the styles directory as specified by the manifest', async () => { - const one = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/1.css') - const two = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/2.less') - const three = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/3.css') + const one = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/1.css' + ) + const two = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/2.less' + ) + const three = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/3.css' + ) expect(atom.themes.stylesheetElementForId(one)).toBeNull() expect(atom.themes.stylesheetElementForId(two)).toBeNull() expect(atom.themes.stylesheetElementForId(three)).toBeNull() - await atom.packages.activatePackage('package-with-style-sheets-manifest') + await atom.packages.activatePackage( + 'package-with-style-sheets-manifest' + ) expect(atom.themes.stylesheetElementForId(one)).not.toBeNull() expect(atom.themes.stylesheetElementForId(two)).not.toBeNull() expect(atom.themes.stylesheetElementForId(three)).toBeNull() - expect(getComputedStyle(document.querySelector('#jasmine-content')).fontSize).toBe('1px') + expect( + getComputedStyle(document.querySelector('#jasmine-content')) + .fontSize + ).toBe('1px') }) }) describe("when the metadata does not contain a 'styleSheets' manifest", () => { it('loads all style sheets from the styles directory', async () => { - const one = require.resolve('./fixtures/packages/package-with-styles/styles/1.css') - const two = require.resolve('./fixtures/packages/package-with-styles/styles/2.less') - const three = require.resolve('./fixtures/packages/package-with-styles/styles/3.test-context.css') - const four = require.resolve('./fixtures/packages/package-with-styles/styles/4.css') + const one = require.resolve( + './fixtures/packages/package-with-styles/styles/1.css' + ) + const two = require.resolve( + './fixtures/packages/package-with-styles/styles/2.less' + ) + const three = require.resolve( + './fixtures/packages/package-with-styles/styles/3.test-context.css' + ) + const four = require.resolve( + './fixtures/packages/package-with-styles/styles/4.css' + ) expect(atom.themes.stylesheetElementForId(one)).toBeNull() expect(atom.themes.stylesheetElementForId(two)).toBeNull() @@ -992,7 +1286,10 @@ describe('PackageManager', () => { expect(atom.themes.stylesheetElementForId(two)).not.toBeNull() expect(atom.themes.stylesheetElementForId(three)).not.toBeNull() expect(atom.themes.stylesheetElementForId(four)).not.toBeNull() - expect(getComputedStyle(document.querySelector('#jasmine-content')).fontSize).toBe('3px') + expect( + getComputedStyle(document.querySelector('#jasmine-content')) + .fontSize + ).toBe('3px') }) }) @@ -1045,18 +1342,23 @@ describe('PackageManager', () => { describe('scoped-property loading', () => { it('loads the scoped properties', async () => { await atom.packages.activatePackage('package-with-settings') - expect(atom.config.get('editor.increaseIndentPattern', {scope: ['.source.omg']})).toBe('^a') + expect( + atom.config.get('editor.increaseIndentPattern', { + scope: ['.source.omg'] + }) + ).toBe('^a') }) }) - - describe("URI handler registration", () => { + describe('URI handler registration', () => { it("registers the package's specified URI handler", async () => { const uri = 'atom://package-with-uri-handler/some/url?with=args' const mod = require('./fixtures/packages/package-with-uri-handler') spyOn(mod, 'handleURI') spyOn(atom.packages, 'hasLoadedInitialPackages').andReturn(true) - const activationPromise = atom.packages.activatePackage('package-with-uri-handler') + const activationPromise = atom.packages.activatePackage( + 'package-with-uri-handler' + ) atom.dispatchURIMessage(uri) await activationPromise expect(mod.handleURI).toHaveBeenCalledWith(url.parse(uri, true), uri) @@ -1070,16 +1372,34 @@ describe('PackageManager', () => { let firstServiceV3Disposed = false let firstServiceV4Disposed = false let secondServiceDisposed = false - spyOn(consumerModule, 'consumeFirstServiceV3').andReturn(new Disposable(() => { firstServiceV3Disposed = true })) - spyOn(consumerModule, 'consumeFirstServiceV4').andReturn(new Disposable(() => { firstServiceV4Disposed = true })) - spyOn(consumerModule, 'consumeSecondService').andReturn(new Disposable(() => { secondServiceDisposed = true })) + spyOn(consumerModule, 'consumeFirstServiceV3').andReturn( + new Disposable(() => { + firstServiceV3Disposed = true + }) + ) + spyOn(consumerModule, 'consumeFirstServiceV4').andReturn( + new Disposable(() => { + firstServiceV4Disposed = true + }) + ) + spyOn(consumerModule, 'consumeSecondService').andReturn( + new Disposable(() => { + secondServiceDisposed = true + }) + ) await atom.packages.activatePackage('package-with-consumed-services') await atom.packages.activatePackage('package-with-provided-services') expect(consumerModule.consumeFirstServiceV3.callCount).toBe(1) - expect(consumerModule.consumeFirstServiceV3).toHaveBeenCalledWith('first-service-v3') - expect(consumerModule.consumeFirstServiceV4).toHaveBeenCalledWith('first-service-v4') - expect(consumerModule.consumeSecondService).toHaveBeenCalledWith('second-service') + expect(consumerModule.consumeFirstServiceV3).toHaveBeenCalledWith( + 'first-service-v3' + ) + expect(consumerModule.consumeFirstServiceV4).toHaveBeenCalledWith( + 'first-service-v4' + ) + expect(consumerModule.consumeSecondService).toHaveBeenCalledWith( + 'second-service' + ) consumerModule.consumeFirstServiceV3.reset() consumerModule.consumeFirstServiceV4.reset() @@ -1101,10 +1421,22 @@ describe('PackageManager', () => { const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - await atom.packages.activatePackage('package-with-missing-consumed-services') - await atom.packages.activatePackage('package-with-missing-provided-services') - expect(atom.packages.isPackageActive('package-with-missing-consumed-services')).toBe(true) - expect(atom.packages.isPackageActive('package-with-missing-provided-services')).toBe(true) + await atom.packages.activatePackage( + 'package-with-missing-consumed-services' + ) + await atom.packages.activatePackage( + 'package-with-missing-provided-services' + ) + expect( + atom.packages.isPackageActive( + 'package-with-missing-consumed-services' + ) + ).toBe(true) + expect( + atom.packages.isPackageActive( + 'package-with-missing-provided-services' + ) + ).toBe(true) expect(addErrorHandler.callCount).toBe(0) }) }) @@ -1115,7 +1447,9 @@ describe('PackageManager', () => { spyOn(atom, 'inSpecMode').andReturn(false) spyOn(console, 'warn') - const badPack = await atom.packages.activatePackage('package-that-throws-on-activate') + const badPack = await atom.packages.activatePackage( + 'package-that-throws-on-activate' + ) spyOn(badPack.mainModule, 'serialize').andCallThrough() atom.packages.serialize() @@ -1128,16 +1462,24 @@ describe('PackageManager', () => { await atom.packages.activatePackage('package-with-serialize-error') await atom.packages.activatePackage('package-with-serialization') atom.packages.serialize() - expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined() - expect(atom.packages.packageStates['package-with-serialization']).toEqual({someNumber: 1}) + expect( + atom.packages.packageStates['package-with-serialize-error'] + ).toBeUndefined() + expect(atom.packages.packageStates['package-with-serialization']).toEqual( + { someNumber: 1 } + ) expect(console.error).toHaveBeenCalled() }) }) describe('::deactivatePackages()', () => { it('deactivates all packages but does not serialize them', async () => { - const pack1 = await atom.packages.activatePackage('package-with-deactivate') - const pack2 = await atom.packages.activatePackage('package-with-serialization') + const pack1 = await atom.packages.activatePackage( + 'package-with-deactivate' + ) + const pack2 = await atom.packages.activatePackage( + 'package-with-serialization' + ) spyOn(pack1.mainModule, 'deactivate') spyOn(pack2.mainModule, 'serialize') @@ -1153,8 +1495,12 @@ describe('PackageManager', () => { it("calls `deactivate` on the package's main module if activate was successful", async () => { spyOn(atom, 'inSpecMode').andReturn(false) - const pack = await atom.packages.activatePackage('package-with-deactivate') - expect(atom.packages.isPackageActive('package-with-deactivate')).toBeTruthy() + const pack = await atom.packages.activatePackage( + 'package-with-deactivate' + ) + expect( + atom.packages.isPackageActive('package-with-deactivate') + ).toBeTruthy() spyOn(pack.mainModule, 'deactivate').andCallThrough() await atom.packages.deactivatePackage('package-with-deactivate') @@ -1162,13 +1508,19 @@ describe('PackageManager', () => { expect(atom.packages.isPackageActive('package-with-module')).toBeFalsy() spyOn(console, 'warn') - const badPack = await atom.packages.activatePackage('package-that-throws-on-activate') - expect(atom.packages.isPackageActive('package-that-throws-on-activate')).toBeTruthy() + const badPack = await atom.packages.activatePackage( + 'package-that-throws-on-activate' + ) + expect( + atom.packages.isPackageActive('package-that-throws-on-activate') + ).toBeTruthy() spyOn(badPack.mainModule, 'deactivate').andCallThrough() await atom.packages.deactivatePackage('package-that-throws-on-activate') expect(badPack.mainModule.deactivate).not.toHaveBeenCalled() - expect(atom.packages.isPackageActive('package-that-throws-on-activate')).toBeFalsy() + expect( + atom.packages.isPackageActive('package-that-throws-on-activate') + ).toBeFalsy() }) it("absorbs exceptions that are thrown by the package module's deactivate method", async () => { @@ -1188,17 +1540,33 @@ describe('PackageManager', () => { it("removes the package's keymaps", async () => { await atom.packages.activatePackage('package-with-keymaps') await atom.packages.deactivatePackage('package-with-keymaps') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: createTestElement('test-1')})).toHaveLength(0) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: createTestElement('test-2')})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: createTestElement('test-1') + }) + ).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: createTestElement('test-2') + }) + ).toHaveLength(0) }) it("removes the package's stylesheets", async () => { await atom.packages.activatePackage('package-with-styles') await atom.packages.deactivatePackage('package-with-styles') - const one = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/1.css') - const two = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/2.less') - const three = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/3.css') + const one = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/1.css' + ) + const two = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/2.less' + ) + const three = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/3.css' + ) expect(atom.themes.stylesheetElementForId(one)).not.toExist() expect(atom.themes.stylesheetElementForId(two)).not.toExist() expect(atom.themes.stylesheetElementForId(three)).not.toExist() @@ -1206,10 +1574,18 @@ describe('PackageManager', () => { it("removes the package's scoped-properties", async () => { await atom.packages.activatePackage('package-with-settings') - expect(atom.config.get('editor.increaseIndentPattern', {scope: ['.source.omg']})).toBe('^a') + expect( + atom.config.get('editor.increaseIndentPattern', { + scope: ['.source.omg'] + }) + ).toBe('^a') await atom.packages.deactivatePackage('package-with-settings') - expect(atom.config.get('editor.increaseIndentPattern', {scope: ['.source.omg']})).toBeUndefined() + expect( + atom.config.get('editor.increaseIndentPattern', { + scope: ['.source.omg'] + }) + ).toBeUndefined() }) it('invokes ::onDidDeactivatePackage listeners with the deactivated package', async () => { @@ -1261,21 +1637,31 @@ describe('PackageManager', () => { expect(themeActivator).toHaveBeenCalled() const packages = packageActivator.mostRecentCall.args[0] - for (let pack of packages) { expect(['atom', 'textmate']).toContain(pack.getType()) } + for (let pack of packages) { + expect(['atom', 'textmate']).toContain(pack.getType()) + } const themes = themeActivator.mostRecentCall.args[0] - themes.map((theme) => expect(['theme']).toContain(theme.getType())) + themes.map(theme => expect(['theme']).toContain(theme.getType())) }) it('calls callbacks registered with ::onDidActivateInitialPackages', async () => { const package1 = atom.packages.loadPackage('package-with-main') const package2 = atom.packages.loadPackage('package-with-index') - const package3 = atom.packages.loadPackage('package-with-activation-commands') - spyOn(atom.packages, 'getLoadedPackages').andReturn([package1, package2, package3]) + const package3 = atom.packages.loadPackage( + 'package-with-activation-commands' + ) + spyOn(atom.packages, 'getLoadedPackages').andReturn([ + package1, + package2, + package3 + ]) spyOn(atom.themes, 'activatePackages') atom.packages.activate() - await new Promise(resolve => atom.packages.onDidActivateInitialPackages(resolve)) + await new Promise(resolve => + atom.packages.onDidActivateInitialPackages(resolve) + ) jasmine.unspy(atom.packages, 'getLoadedPackages') expect(atom.packages.getActivePackages().includes(package1)).toBe(true) @@ -1293,11 +1679,15 @@ describe('PackageManager', () => { expect(atom.config.get('core.disabledPackages')).toContain(packageName) const pack = atom.packages.enablePackage(packageName) - await new Promise(resolve => atom.packages.onDidActivatePackage(resolve)) + await new Promise(resolve => + atom.packages.onDidActivatePackage(resolve) + ) expect(atom.packages.getLoadedPackages()).toContain(pack) expect(atom.packages.getActivePackages()).toContain(pack) - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) }) it('disables an enabled package', async () => { @@ -1305,7 +1695,9 @@ describe('PackageManager', () => { const pack = await atom.packages.activatePackage(packageName) atom.packages.observeDisabledPackages() - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) await new Promise(resolve => { atom.packages.onDidDeactivatePackage(resolve) atom.packages.disablePackage(packageName) @@ -1328,7 +1720,9 @@ describe('PackageManager', () => { expect(atom.config.get('core.disabledPackages')).toContain(packageName) atom.packages.disablePackage(packageName) - const packagesDisabled = atom.config.get('core.disabledPackages').filter(pack => pack === packageName) + const packagesDisabled = atom.config + .get('core.disabledPackages') + .filter(pack => pack === packageName) expect(packagesDisabled.length).toEqual(1) }) }) @@ -1340,14 +1734,20 @@ describe('PackageManager', () => { it('enables and disables a theme', async () => { const packageName = 'theme-with-package-file' expect(atom.config.get('core.themes')).not.toContain(packageName) - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) // enabling of theme const pack = atom.packages.enablePackage(packageName) - await new Promise(resolve => atom.packages.onDidActivatePackage(resolve)) + await new Promise(resolve => + atom.packages.onDidActivatePackage(resolve) + ) expect(atom.packages.isPackageActive(packageName)).toBe(true) expect(atom.config.get('core.themes')).toContain(packageName) - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) await new Promise(resolve => { atom.themes.onDidChangeActiveThemes(resolve) @@ -1357,7 +1757,9 @@ describe('PackageManager', () => { expect(atom.packages.getActivePackages()).not.toContain(pack) expect(atom.config.get('core.themes')).not.toContain(packageName) expect(atom.config.get('core.themes')).not.toContain(packageName) - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) }) }) }) diff --git a/spec/package-transpilation-registry-spec.js b/spec/package-transpilation-registry-spec.js index 214f1177e..90a06ea6c 100644 --- a/spec/package-transpilation-registry-spec.js +++ b/spec/package-transpilation-registry-spec.js @@ -2,17 +2,24 @@ import fs from 'fs' import path from 'path' -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} 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 +27,7 @@ const originalCompiler = { } } -describe("PackageTranspilationRegistry", () => { +describe('PackageTranspilationRegistry', () => { let registry let wrappedCompiler @@ -47,20 +54,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 +93,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 +103,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 +112,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) }) }) }) diff --git a/spec/pane-container-spec.js b/spec/pane-container-spec.js index 060808d0b..50a60d2b0 100644 --- a/spec/pane-container-spec.js +++ b/spec/pane-container-spec.js @@ -1,11 +1,20 @@ const PaneContainer = require('../src/pane-container') -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = 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 +30,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 +77,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 +91,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 +104,7 @@ describe('PaneContainer', () => { expect(leftPane.getItems().length).toBe(1) expect(rightPane.getItems().length).toBe(1) - }) - ) + })) }) }) @@ -144,8 +155,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 +175,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 +201,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 +262,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 +312,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 +321,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 +354,7 @@ describe('PaneContainer', () => { pane2.destroy() - expect(events).toEqual([[{pane: pane2}, {itemsDestroyed: [false]}]]) + expect(events).toEqual([[{ pane: pane2 }, { itemsDestroyed: [false] }]]) }) }) @@ -340,7 +362,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 +374,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 +391,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 +411,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 +436,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 +480,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) - }) - ) + })) }) }) diff --git a/spec/pane-spec.js b/spec/pane-spec.js index ddb92b96e..b87e9e8ad 100644 --- a/spec/pane-spec.js +++ b/spec/pane-spec.js @@ -1,15 +1,23 @@ -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, + fit, + ffit, + fffit, + 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 +28,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 +81,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 +161,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 +189,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 +213,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 +255,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 +271,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 +287,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 +298,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 +311,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 +344,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 +407,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 +423,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 +464,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 +483,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 +496,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 +518,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 +541,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 +579,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 +599,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 +608,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 +670,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 +695,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 +726,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 +753,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 +768,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 +785,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 +800,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 +815,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 +826,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 +840,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 +873,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 +904,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 +928,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 +948,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 +961,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 +991,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 +1009,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 +1027,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 +1053,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 +1064,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 +1083,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 +1093,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 +1129,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 +1139,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 +1151,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 +1164,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 +1173,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 +1194,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 +1206,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 +1215,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 +1230,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 +1242,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 +1251,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 +1266,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 +1278,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 +1287,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 +1302,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 +1317,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 +1331,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 +1351,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 +1368,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 +1386,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 +1408,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 +1458,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 +1489,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 +1503,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 +1512,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 +1561,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 +1584,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 +1624,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 +1652,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) diff --git a/spec/panel-container-element-spec.js b/spec/panel-container-element-spec.js index 5634883df..039061ae8 100644 --- a/spec/panel-container-element-spec.js +++ b/spec/panel-container-element-spec.js @@ -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() diff --git a/spec/panel-container-spec.js b/spec/panel-container-spec.js index f5537f0b8..35286cd36 100644 --- a/spec/panel-container-spec.js +++ b/spec/panel-container-spec.js @@ -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) }) }) diff --git a/spec/panel-spec.js b/spec/panel-spec.js index 8df51a2fb..7e1365a67 100644 --- a/spec/panel-spec.js +++ b/spec/panel-spec.js @@ -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') diff --git a/spec/path-watcher-spec.js b/spec/path-watcher-spec.js index ae5cd7d75..050f9df45 100644 --- a/spec/path-watcher-spec.js +++ b/spec/path-watcher-spec.js @@ -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([ diff --git a/spec/project-spec.js b/spec/project-spec.js index 861a0f53a..2025cae71 100644 --- a/spec/project-spec.js +++ b/spec/project-spec.js @@ -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) diff --git a/spec/reopen-project-menu-manager-spec.js b/spec/reopen-project-menu-manager-spec.js index b11561c31..100111242 100644 --- a/spec/reopen-project-menu-manager-spec.js +++ b/spec/reopen-project-menu-manager-spec.js @@ -1,19 +1,25 @@ /** @babel */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' -import {Emitter, Disposable, CompositeDisposable} from 'event-kit' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' +import { Emitter, Disposable, CompositeDisposable } from 'event-kit' const ReopenProjectMenuManager = require('../src/reopen-project-menu-manager') 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 @@ -28,43 +34,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 +91,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'] + 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', () => { + 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', () => { + 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 +153,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 +165,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 +175,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 +193,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 +215,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 +233,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') }) }) diff --git a/spec/selection-spec.js b/spec/selection-spec.js index e9cf1c617..5dc6cd199 100644 --- a/spec/selection-spec.js +++ b/spec/selection-spec.js @@ -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 }) }) } }) diff --git a/spec/state-store-spec.js b/spec/state-store-spec.js index 0b62066c8..95583f8cd 100644 --- a/spec/state-store-spec.js +++ b/spec/state-store-spec.js @@ -1,68 +1,76 @@ /** @babel */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} 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) }) }) diff --git a/spec/style-manager-spec.js b/spec/style-manager-spec.js index 641c93709..e29dedb0c 100644 --- a/spec/style-manager-spec.js +++ b/spec/style-manager-spec.js @@ -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'}) + const disposable1 = 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}', diff --git a/spec/syntax-scope-map-spec.js b/spec/syntax-scope-map-spec.js index 15b44095c..ec52c24b6 100644 --- a/spec/syntax-scope-map-spec.js +++ b/spec/syntax-scope-map-spec.js @@ -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' }) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index dbad4a3e7..d58a749d6 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -1,19 +1,31 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach, + conditionPromise, + timeoutPromise +} = require('./async-spec-helpers') const Random = require('../script/node_modules/random-seed') -const {getRandomBufferRange, buildRandomLines} = require('./helpers/random') +const { getRandomBufferRange, buildRandomLines } = require('./helpers/random') const TextEditorComponent = require('../src/text-editor-component') const TextEditorElement = require('../src/text-editor-element') const TextEditor = require('../src/text-editor') const TextBuffer = require('text-buffer') -const {Point} = TextBuffer +const { Point } = TextBuffer const fs = require('fs') const path = require('path') const Grim = require('grim') const electron = require('electron') const clipboard = electron.clipboard -const SAMPLE_TEXT = fs.readFileSync(path.join(__dirname, 'fixtures', 'sample.js'), 'utf8') +const SAMPLE_TEXT = fs.readFileSync( + path.join(__dirname, 'fixtures', 'sample.js'), + 'utf8' +) document.registerElement('text-editor-component-test-element', { prototype: Object.create(HTMLElement.prototype, { @@ -34,11 +46,16 @@ describe('TextEditorComponent', () => { // 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) if (verticalScrollbarWidth == null) { - const {component, element} = buildComponent({text: 'abcdefgh\n'.repeat(10), width: 30, height: 30}) + const { component, element } = buildComponent({ + text: 'abcdefgh\n'.repeat(10), + width: 30, + height: 30 + }) verticalScrollbarWidth = getVerticalScrollbarWidth(component) horizontalScrollbarHeight = getHorizontalScrollbarHeight(component) element.remove() @@ -54,7 +71,10 @@ describe('TextEditorComponent', () => { describe('rendering', () => { it('renders lines and line numbers for the visible region', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) expect(queryOnScreenLineNumberElements(element).length).toBe(13) expect(queryOnScreenLineElements(element).length).toBe(13) @@ -69,13 +89,19 @@ describe('TextEditorComponent', () => { // After scrolling down beyond > 3 rows, the order of line numbers and lines // in the DOM is a bit weird because the first tile is recycled to the bottom // when it is scrolled out of view - expect(queryOnScreenLineNumberElements(element).map(element => element.textContent.trim())).toEqual([ - '10', '11', '12', '4', '5', '6', '7', '8', '9' - ]) - expect(queryOnScreenLineElements(element).map(element => element.dataset.screenRow)).toEqual([ - '9', '10', '11', '3', '4', '5', '6', '7', '8' - ]) - expect(queryOnScreenLineElements(element).map(element => element.textContent)).toEqual([ + expect( + queryOnScreenLineNumberElements(element).map(element => + element.textContent.trim() + ) + ).toEqual(['10', '11', '12', '4', '5', '6', '7', '8', '9']) + expect( + queryOnScreenLineElements(element).map( + element => element.dataset.screenRow + ) + ).toEqual(['9', '10', '11', '3', '4', '5', '6', '7', '8']) + expect( + queryOnScreenLineElements(element).map(element => element.textContent) + ).toEqual([ editor.lineTextForScreenRow(9), ' ', // this line is blank in the model, but we render a space to prevent the line from collapsing vertically editor.lineTextForScreenRow(11), @@ -88,13 +114,19 @@ describe('TextEditorComponent', () => { ]) await setScrollTop(component, 2.5 * component.getLineHeight()) - expect(queryOnScreenLineNumberElements(element).map(element => element.textContent.trim())).toEqual([ - '1', '2', '3', '4', '5', '6', '7', '8', '9' - ]) - expect(queryOnScreenLineElements(element).map(element => element.dataset.screenRow)).toEqual([ - '0', '1', '2', '3', '4', '5', '6', '7', '8' - ]) - expect(queryOnScreenLineElements(element).map(element => element.textContent)).toEqual([ + expect( + queryOnScreenLineNumberElements(element).map(element => + element.textContent.trim() + ) + ).toEqual(['1', '2', '3', '4', '5', '6', '7', '8', '9']) + expect( + queryOnScreenLineElements(element).map( + element => element.dataset.screenRow + ) + ).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8']) + expect( + queryOnScreenLineElements(element).map(element => element.textContent) + ).toEqual([ editor.lineTextForScreenRow(0), editor.lineTextForScreenRow(1), editor.lineTextForScreenRow(2), @@ -108,22 +140,30 @@ describe('TextEditorComponent', () => { }) it('bases the width of the lines div on the width of the longest initially-visible screen line', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, height: 20, width: 100}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + height: 20, + width: 100 + }) { expect(editor.getApproximateLongestScreenRow()).toBe(3) const expectedWidth = Math.ceil( component.pixelPositionForScreenPosition(Point(3, Infinity)).left + - component.getBaseCharacterWidth() + component.getBaseCharacterWidth() + ) + expect(element.querySelector('.lines').style.width).toBe( + expectedWidth + 'px' ) - expect(element.querySelector('.lines').style.width).toBe(expectedWidth + 'px') } { // Get the next update promise synchronously here to ensure we don't // miss the update while polling the condition. const nextUpdatePromise = component.getNextUpdatePromise() - await conditionPromise(() => editor.getApproximateLongestScreenRow() === 6) + await conditionPromise( + () => editor.getApproximateLongestScreenRow() === 6 + ) await nextUpdatePromise // Capture the width of the lines before requesting the width of @@ -131,7 +171,7 @@ describe('TextEditorComponent', () => { const actualWidth = element.querySelector('.lines').style.width const expectedWidth = Math.ceil( component.pixelPositionForScreenPosition(Point(6, Infinity)).left + - component.getBaseCharacterWidth() + component.getBaseCharacterWidth() ) expect(actualWidth).toBe(expectedWidth + 'px') } @@ -154,7 +194,10 @@ describe('TextEditorComponent', () => { }) it('re-renders lines when their height changes', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) element.style.height = 4 * component.measurements.lineHeight + 'px' await component.getNextUpdatePromise() expect(queryOnScreenLineNumberElements(element).length).toBe(9) @@ -192,84 +235,119 @@ describe('TextEditorComponent', () => { }) it('makes the content at least as tall as the scroll container client height', async () => { - const {component, element, editor} = buildComponent({text: 'a'.repeat(100), width: 50, height: 100}) - expect(component.refs.content.offsetHeight).toBe(100 - getHorizontalScrollbarHeight(component)) + const { component, element, editor } = buildComponent({ + text: 'a'.repeat(100), + width: 50, + height: 100 + }) + expect(component.refs.content.offsetHeight).toBe( + 100 - getHorizontalScrollbarHeight(component) + ) editor.setText('a\n'.repeat(30)) await component.getNextUpdatePromise() expect(component.refs.content.offsetHeight).toBeGreaterThan(100) - expect(component.refs.content.offsetHeight).toBe(component.getContentHeight()) + expect(component.refs.content.offsetHeight).toBe( + component.getContentHeight() + ) }) it('honors the scrollPastEnd option by adding empty space equivalent to the clientHeight to the end of the content area', async () => { - const {component, element, editor} = buildComponent({autoHeight: false, autoWidth: false}) - const {scrollContainer} = component.refs + const { component, element, editor } = buildComponent({ + autoHeight: false, + autoWidth: false + }) + const { scrollContainer } = component.refs - await editor.update({scrollPastEnd: true}) + await editor.update({ scrollPastEnd: true }) await setEditorHeightInLines(component, 6) // scroll to end await setScrollTop(component, Infinity) - expect(component.getFirstVisibleRow()).toBe(editor.getScreenLineCount() - 3) + expect(component.getFirstVisibleRow()).toBe( + editor.getScreenLineCount() - 3 + ) - editor.update({scrollPastEnd: false}) + editor.update({ scrollPastEnd: false }) await component.getNextUpdatePromise() // wait for scrollable content resize - expect(component.getFirstVisibleRow()).toBe(editor.getScreenLineCount() - 6) + expect(component.getFirstVisibleRow()).toBe( + editor.getScreenLineCount() - 6 + ) // Always allows at least 3 lines worth of overscroll if the editor is short await setEditorHeightInLines(component, 2) - await editor.update({scrollPastEnd: true}) + await editor.update({ scrollPastEnd: true }) await setScrollTop(component, Infinity) - expect(component.getFirstVisibleRow()).toBe(editor.getScreenLineCount() + 1) + expect(component.getFirstVisibleRow()).toBe( + editor.getScreenLineCount() + 1 + ) }) it('does not fire onDidChangeScrollTop listeners when assigning the same maximal value and the content height has fractional pixels (regression)', async () => { - const {component, element, editor} = buildComponent({autoHeight: false, autoWidth: false}) + const { component, element, editor } = buildComponent({ + autoHeight: false, + autoWidth: false + }) await setEditorHeightInLines(component, 3) // Force a fractional content height with a block decoration - const item = document.createElement("div") + const item = document.createElement('div') item.style.height = '10.6px' - editor.decorateMarker(editor.markBufferPosition([0, 0]), {type: "block", item}) + editor.decorateMarker(editor.markBufferPosition([0, 0]), { + type: 'block', + item + }) await component.getNextUpdatePromise() component.setScrollTop(Infinity) - element.onDidChangeScrollTop((newScrollTop) => { + element.onDidChangeScrollTop(newScrollTop => { throw new Error('Scroll top should not have changed') }) component.setScrollTop(component.getScrollTop()) }) it('gives the line number tiles an explicit width and height so their layout can be strictly contained', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3}) + const { component, element, editor } = buildComponent({ rowsPerTile: 3 }) - const lineNumberGutterElement = component.refs.gutterContainer.refs.lineNumberGutter.element - expect(lineNumberGutterElement.offsetHeight).toBe(component.getScrollHeight()) + const lineNumberGutterElement = + component.refs.gutterContainer.refs.lineNumberGutter.element + expect(lineNumberGutterElement.offsetHeight).toBe( + component.getScrollHeight() + ) for (const child of lineNumberGutterElement.children) { expect(child.offsetWidth).toBe(lineNumberGutterElement.offsetWidth) if (!child.classList.contains('line-number')) { for (const lineNumberElement of child.children) { - expect(lineNumberElement.offsetWidth).toBe(lineNumberGutterElement.offsetWidth) + expect(lineNumberElement.offsetWidth).toBe( + lineNumberGutterElement.offsetWidth + ) } } } editor.setText('x\n'.repeat(99)) await component.getNextUpdatePromise() - expect(lineNumberGutterElement.offsetHeight).toBe(component.getScrollHeight()) + expect(lineNumberGutterElement.offsetHeight).toBe( + component.getScrollHeight() + ) for (const child of lineNumberGutterElement.children) { expect(child.offsetWidth).toBe(lineNumberGutterElement.offsetWidth) if (!child.classList.contains('line-number')) { for (const lineNumberElement of child.children) { - expect(lineNumberElement.offsetWidth).toBe(lineNumberGutterElement.offsetWidth) + expect(lineNumberElement.offsetWidth).toBe( + lineNumberGutterElement.offsetWidth + ) } } } }) it('keeps the number of tiles stable when the visible line count changes during vertical scrolling', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) await setEditorHeightInLines(component, 5.5) expect(component.refs.lineTiles.children.length).toBe(3 + 2) // account for cursors and highlights containers @@ -281,7 +359,10 @@ describe('TextEditorComponent', () => { }) it('recycles tiles on resize', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 7) await setScrollTop(component, 3.5 * component.getLineHeight()) const lineNode = lineNodeForScreenRow(component, 7) @@ -289,42 +370,68 @@ describe('TextEditorComponent', () => { expect(lineNodeForScreenRow(component, 7)).toBe(lineNode) }) - it('updates lines numbers when a row\'s foldability changes (regression)', async () => { - const {component, element, editor} = buildComponent({text: 'abc\n'}) + it("updates lines numbers when a row's foldability changes (regression)", async () => { + const { component, element, editor } = buildComponent({ text: 'abc\n' }) editor.setCursorBufferPosition([1, 0]) await component.getNextUpdatePromise() - expect(lineNumberNodeForScreenRow(component, 0).querySelector('.foldable')).toBeNull() + expect( + lineNumberNodeForScreenRow(component, 0).querySelector('.foldable') + ).toBeNull() editor.insertText(' def') await component.getNextUpdatePromise() - expect(lineNumberNodeForScreenRow(component, 0).querySelector('.foldable')).toBeDefined() + expect( + lineNumberNodeForScreenRow(component, 0).querySelector('.foldable') + ).toBeDefined() editor.undo() await component.getNextUpdatePromise() - expect(lineNumberNodeForScreenRow(component, 0).querySelector('.foldable')).toBeNull() + expect( + lineNumberNodeForScreenRow(component, 0).querySelector('.foldable') + ).toBeNull() }) it('shows the foldable icon on the last screen row of a buffer row that can be folded', async () => { - const {component, element, editor} = buildComponent({text: 'abc\n de\nfghijklm\n no', softWrapped: true}) + const { component, element, editor } = buildComponent({ + text: 'abc\n de\nfghijklm\n no', + softWrapped: true + }) await setEditorWidthInCharacters(component, 5) - expect(lineNumberNodeForScreenRow(component, 0).classList.contains('foldable')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('foldable')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('foldable')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 3).classList.contains('foldable')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 4).classList.contains('foldable')).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 0).classList.contains('foldable') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('foldable') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('foldable') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 3).classList.contains('foldable') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 4).classList.contains('foldable') + ).toBe(false) }) it('renders dummy vertical and horizontal scrollbars when content overflows', async () => { - const {component, element, editor} = buildComponent({height: 100, width: 100}) + const { component, element, editor } = buildComponent({ + height: 100, + width: 100 + }) const verticalScrollbar = component.refs.verticalScrollbar.element const horizontalScrollbar = component.refs.horizontalScrollbar.element expect(verticalScrollbar.scrollHeight).toBe(component.getContentHeight()) expect(horizontalScrollbar.scrollWidth).toBe(component.getContentWidth()) expect(getVerticalScrollbarWidth(component)).toBeGreaterThan(0) expect(getHorizontalScrollbarHeight(component)).toBeGreaterThan(0) - expect(verticalScrollbar.style.bottom).toBe(getVerticalScrollbarWidth(component) + 'px') + expect(verticalScrollbar.style.bottom).toBe( + getVerticalScrollbarWidth(component) + 'px' + ) expect(verticalScrollbar.style.visibility).toBe('') - expect(horizontalScrollbar.style.right).toBe(getHorizontalScrollbarHeight(component) + 'px') + expect(horizontalScrollbar.style.right).toBe( + getHorizontalScrollbarHeight(component) + 'px' + ) expect(horizontalScrollbar.style.visibility).toBe('') expect(component.refs.scrollbarCorner).toBeDefined() @@ -363,7 +470,10 @@ describe('TextEditorComponent', () => { describe('when scrollbar styles change or the editor element is detached and then reattached', () => { it('updates the bottom/right of dummy scrollbars and client height/width measurements', async () => { - const {component, element, editor} = buildComponent({height: 100, width: 100}) + const { component, element, editor } = buildComponent({ + height: 100, + width: 100 + }) expect(getHorizontalScrollbarHeight(component)).toBeGreaterThan(10) expect(getVerticalScrollbarWidth(component)).toBeGreaterThan(10) setScrollTop(component, 20) @@ -379,12 +489,18 @@ describe('TextEditorComponent', () => { expect(getHorizontalScrollbarHeight(component)).toBe(10) expect(getVerticalScrollbarWidth(component)).toBe(10) - expect(component.refs.horizontalScrollbar.element.style.right).toBe('10px') - expect(component.refs.verticalScrollbar.element.style.bottom).toBe('10px') + expect(component.refs.horizontalScrollbar.element.style.right).toBe( + '10px' + ) + expect(component.refs.verticalScrollbar.element.style.bottom).toBe( + '10px' + ) expect(component.refs.horizontalScrollbar.element.scrollLeft).toBe(10) expect(component.refs.verticalScrollbar.element.scrollTop).toBe(20) expect(component.getScrollContainerClientHeight()).toBe(100 - 10) - expect(component.getScrollContainerClientWidth()).toBe(100 - component.getGutterContainerWidth() - 10) + expect(component.getScrollContainerClientWidth()).toBe( + 100 - component.getGutterContainerWidth() - 10 + ) // Detaching and re-attaching the editor element. element.remove() @@ -392,15 +508,21 @@ describe('TextEditorComponent', () => { expect(getHorizontalScrollbarHeight(component)).toBe(10) expect(getVerticalScrollbarWidth(component)).toBe(10) - expect(component.refs.horizontalScrollbar.element.style.right).toBe('10px') - expect(component.refs.verticalScrollbar.element.style.bottom).toBe('10px') + expect(component.refs.horizontalScrollbar.element.style.right).toBe( + '10px' + ) + expect(component.refs.verticalScrollbar.element.style.bottom).toBe( + '10px' + ) expect(component.refs.horizontalScrollbar.element.scrollLeft).toBe(10) expect(component.refs.verticalScrollbar.element.scrollTop).toBe(20) expect(component.getScrollContainerClientHeight()).toBe(100 - 10) - expect(component.getScrollContainerClientWidth()).toBe(100 - component.getGutterContainerWidth() - 10) + expect(component.getScrollContainerClientWidth()).toBe( + 100 - component.getGutterContainerWidth() - 10 + ) // Ensure we don't throw an error trying to remeasure non-existent scrollbars for mini editors. - await editor.update({mini: true}) + await editor.update({ mini: true }) TextEditor.didUpdateScrollbarStyles() component.scheduleUpdate() await component.getNextUpdatePromise() @@ -408,19 +530,22 @@ describe('TextEditorComponent', () => { }) it('renders cursors within the visible row range', async () => { - const {component, element, editor} = buildComponent({height: 40, rowsPerTile: 2}) + const { component, element, editor } = buildComponent({ + height: 40, + rowsPerTile: 2 + }) await setScrollTop(component, 100) expect(component.getRenderedStartRow()).toBe(4) expect(component.getRenderedEndRow()).toBe(10) - editor.setCursorScreenPosition([0, 0], {autoscroll: false}) // out of view - editor.addCursorAtScreenPosition([2, 2], {autoscroll: false}) // out of view - editor.addCursorAtScreenPosition([4, 0], {autoscroll: false}) // line start - editor.addCursorAtScreenPosition([4, 4], {autoscroll: false}) // at token boundary - editor.addCursorAtScreenPosition([4, 6], {autoscroll: false}) // within token - editor.addCursorAtScreenPosition([5, Infinity], {autoscroll: false}) // line end - editor.addCursorAtScreenPosition([10, 2], {autoscroll: false}) // out of view + editor.setCursorScreenPosition([0, 0], { autoscroll: false }) // out of view + editor.addCursorAtScreenPosition([2, 2], { autoscroll: false }) // out of view + editor.addCursorAtScreenPosition([4, 0], { autoscroll: false }) // line start + editor.addCursorAtScreenPosition([4, 4], { autoscroll: false }) // at token boundary + editor.addCursorAtScreenPosition([4, 6], { autoscroll: false }) // within token + editor.addCursorAtScreenPosition([5, Infinity], { autoscroll: false }) // line end + editor.addCursorAtScreenPosition([10, 2], { autoscroll: false }) // out of view await component.getNextUpdatePromise() let cursorNodes = Array.from(element.querySelectorAll('.cursor')) @@ -430,31 +555,28 @@ describe('TextEditorComponent', () => { verifyCursorPosition(component, cursorNodes[2], 4, 6) verifyCursorPosition(component, cursorNodes[3], 5, 30) - editor.setCursorScreenPosition([8, 11], {autoscroll: false}) + editor.setCursorScreenPosition([8, 11], { autoscroll: false }) await component.getNextUpdatePromise() cursorNodes = Array.from(element.querySelectorAll('.cursor')) expect(cursorNodes.length).toBe(1) verifyCursorPosition(component, cursorNodes[0], 8, 11) - editor.setCursorScreenPosition([0, 0], {autoscroll: false}) + editor.setCursorScreenPosition([0, 0], { autoscroll: false }) await component.getNextUpdatePromise() cursorNodes = Array.from(element.querySelectorAll('.cursor')) expect(cursorNodes.length).toBe(0) - editor.setSelectedScreenRange([[8, 0], [12, 0]], {autoscroll: false}) + editor.setSelectedScreenRange([[8, 0], [12, 0]], { autoscroll: false }) await component.getNextUpdatePromise() cursorNodes = Array.from(element.querySelectorAll('.cursor')) expect(cursorNodes.length).toBe(0) }) it('hides cursors with non-empty selections when showCursorOnSelection is false', async () => { - const {component, element, editor} = buildComponent() - editor.setSelectedScreenRanges([ - [[0, 0], [0, 3]], - [[1, 0], [1, 0]] - ]) + const { component, element, editor } = buildComponent() + editor.setSelectedScreenRanges([[[0, 0], [0, 3]], [[1, 0], [1, 0]]]) await component.getNextUpdatePromise() { const cursorNodes = Array.from(element.querySelectorAll('.cursor')) @@ -463,7 +585,7 @@ describe('TextEditorComponent', () => { verifyCursorPosition(component, cursorNodes[1], 1, 0) } - editor.update({showCursorOnSelection: false}) + editor.update({ showCursorOnSelection: false }) await component.getNextUpdatePromise() { const cursorNodes = Array.from(element.querySelectorAll('.cursor')) @@ -471,10 +593,7 @@ describe('TextEditorComponent', () => { verifyCursorPosition(component, cursorNodes[0], 1, 0) } - editor.setSelectedScreenRanges([ - [[0, 0], [0, 3]], - [[1, 0], [1, 4]] - ]) + editor.setSelectedScreenRanges([[[0, 0], [0, 3]], [[1, 0], [1, 4]]]) await component.getNextUpdatePromise() { const cursorNodes = Array.from(element.querySelectorAll('.cursor')) @@ -484,7 +603,7 @@ describe('TextEditorComponent', () => { it('blinks cursors when the editor is focused and the cursors are not moving', async () => { assertDocumentFocused() - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() component.props.cursorBlinkPeriod = 40 component.props.cursorBlinkResumeDelay = 40 editor.addCursorAtScreenPosition([1, 0]) @@ -493,14 +612,20 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise() const [cursor1, cursor2] = element.querySelectorAll('.cursor') - await conditionPromise(() => - getComputedStyle(cursor1).opacity === '1' && getComputedStyle(cursor2).opacity === '1' + await conditionPromise( + () => + getComputedStyle(cursor1).opacity === '1' && + getComputedStyle(cursor2).opacity === '1' ) - await conditionPromise(() => - getComputedStyle(cursor1).opacity === '0' && getComputedStyle(cursor2).opacity === '0' + await conditionPromise( + () => + getComputedStyle(cursor1).opacity === '0' && + getComputedStyle(cursor2).opacity === '0' ) - await conditionPromise(() => - getComputedStyle(cursor1).opacity === '1' && getComputedStyle(cursor2).opacity === '1' + await conditionPromise( + () => + getComputedStyle(cursor1).opacity === '1' && + getComputedStyle(cursor2).opacity === '1' ) editor.moveRight() @@ -511,13 +636,15 @@ describe('TextEditorComponent', () => { }) it('gives cursors at the end of lines the width of an "x" character', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.setText('abcde') await setEditorWidthInCharacters(component, 5.5) editor.setCursorScreenPosition([0, Infinity]) await component.getNextUpdatePromise() - expect(element.querySelector('.cursor').offsetWidth).toBe(Math.round(component.getBaseCharacterWidth())) + expect(element.querySelector('.cursor').offsetWidth).toBe( + Math.round(component.getBaseCharacterWidth()) + ) // Clip cursor width when soft-wrap is on and the cursor is at the end of // the line. This prevents the parent tile from disabling sub-pixel @@ -525,11 +652,13 @@ describe('TextEditorComponent', () => { // container doesn't solve this issue so we're adding this workaround instead. editor.setSoftWrapped(true) await component.getNextUpdatePromise() - expect(element.querySelector('.cursor').offsetWidth).toBeLessThan(Math.round(component.getBaseCharacterWidth())) + expect(element.querySelector('.cursor').offsetWidth).toBeLessThan( + Math.round(component.getBaseCharacterWidth()) + ) }) it('positions and sizes cursors correctly when they are located next to a fold marker', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.foldBufferRange([[0, 3], [0, 6]]) editor.setCursorScreenPosition([0, 3]) @@ -542,7 +671,9 @@ describe('TextEditorComponent', () => { }) it('positions cursors and placeholder text correctly when the lines container has a margin and/or is padded', async () => { - const {component, element, editor} = buildComponent({placeholderText: 'testing'}) + const { component, element, editor } = buildComponent({ + placeholderText: 'testing' + }) component.refs.lineTiles.style.marginLeft = '10px' TextEditor.didUpdateStyles() @@ -569,14 +700,20 @@ describe('TextEditorComponent', () => { editor.setText('') await component.getNextUpdatePromise() - const placeholderTextLeft = element.querySelector('.placeholder-text').getBoundingClientRect().left + const placeholderTextLeft = element + .querySelector('.placeholder-text') + .getBoundingClientRect().left const linesLeft = component.refs.lineTiles.getBoundingClientRect().left expect(placeholderTextLeft).toBe(linesLeft) }) it('places the hidden input element at the location of the last cursor if it is visible', async () => { - const {component, element, editor} = buildComponent({height: 60, width: 120, rowsPerTile: 2}) - const {hiddenInput} = component.refs.cursorsAndInput.refs + const { component, element, editor } = buildComponent({ + height: 60, + width: 120, + rowsPerTile: 2 + }) + const { hiddenInput } = component.refs.cursorsAndInput.refs setScrollTop(component, 100) await setScrollLeft(component, 40) @@ -591,21 +728,25 @@ describe('TextEditorComponent', () => { // Otherwise it is positioned at the last cursor position editor.addCursorAtScreenPosition([7, 4]) await component.getNextUpdatePromise() - expect(hiddenInput.getBoundingClientRect().top).toBe(clientTopForLine(component, 7)) - expect(Math.round(hiddenInput.getBoundingClientRect().left)).toBe(clientLeftForCharacter(component, 7, 4)) + expect(hiddenInput.getBoundingClientRect().top).toBe( + clientTopForLine(component, 7) + ) + expect(Math.round(hiddenInput.getBoundingClientRect().left)).toBe( + clientLeftForCharacter(component, 7, 4) + ) }) it('soft wraps lines based on the content width when soft wrap is enabled', async () => { let baseCharacterWidth, gutterContainerWidth { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() baseCharacterWidth = component.getBaseCharacterWidth() gutterContainerWidth = component.getGutterContainerWidth() editor.destroy() } - const {component, element, editor} = buildComponent({ - width: gutterContainerWidth + (baseCharacterWidth * 55), + const { component, element, editor } = buildComponent({ + width: gutterContainerWidth + baseCharacterWidth * 55, attach: false }) editor.setSoftWrapped(true) @@ -627,13 +768,18 @@ describe('TextEditorComponent', () => { ' = [], right = [];' ) - const {scrollContainer} = component.refs + const { scrollContainer } = component.refs expect(scrollContainer.clientWidth).toBe(scrollContainer.scrollWidth) }) it('correctly forces the display layer to index visible rows when resizing (regression)', async () => { const text = 'a'.repeat(30) + '\n' + 'b'.repeat(1000) - const {component, element, editor} = buildComponent({height: 300, width: 800, attach: false, text}) + const { component, element, editor } = buildComponent({ + height: 300, + width: 800, + attach: false, + text + }) editor.setSoftWrapped(true) jasmine.attachToDOM(element) @@ -643,38 +789,45 @@ describe('TextEditorComponent', () => { }) it('decorates the line numbers of folded lines', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.foldBufferRow(1) await component.getNextUpdatePromise() - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('folded')).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('folded') + ).toBe(true) }) it('makes lines at least as wide as the scrollContainer', async () => { - const {component, element, editor} = buildComponent() - const {scrollContainer, gutterContainer} = component.refs + const { component, element, editor } = buildComponent() + const { scrollContainer, gutterContainer } = component.refs editor.setText('a') await component.getNextUpdatePromise() - expect(element.querySelector('.line').offsetWidth).toBe(scrollContainer.offsetWidth - verticalScrollbarWidth) + expect(element.querySelector('.line').offsetWidth).toBe( + scrollContainer.offsetWidth - verticalScrollbarWidth + ) }) it('resizes based on the content when the autoHeight and/or autoWidth options are true', async () => { - const {component, element, editor} = buildComponent({autoHeight: true, autoWidth: true}) + const { component, element, editor } = buildComponent({ + autoHeight: true, + autoWidth: true + }) const editorPadding = 3 element.style.padding = editorPadding + 'px' - const {gutterContainer, scrollContainer} = component.refs + const { gutterContainer, scrollContainer } = component.refs const initialWidth = element.offsetWidth const initialHeight = element.offsetHeight expect(initialWidth).toBe( component.getGutterContainerWidth() + - component.getContentWidth() + - verticalScrollbarWidth + - 2 * editorPadding + component.getContentWidth() + + verticalScrollbarWidth + + 2 * editorPadding ) expect(initialHeight).toBe( component.getContentHeight() + - horizontalScrollbarHeight + - 2 * editorPadding + horizontalScrollbarHeight + + 2 * editorPadding ) // When autoWidth is enabled, width adjusts to content @@ -683,9 +836,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise() expect(element.offsetWidth).toBe( component.getGutterContainerWidth() + - component.getContentWidth() + - verticalScrollbarWidth + - 2 * editorPadding + component.getContentWidth() + + verticalScrollbarWidth + + 2 * editorPadding ) expect(element.offsetWidth).toBeGreaterThan(initialWidth) @@ -694,48 +847,79 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise() expect(element.offsetHeight).toBe( component.getContentHeight() + - horizontalScrollbarHeight + - 2 * editorPadding + horizontalScrollbarHeight + + 2 * editorPadding ) expect(element.offsetHeight).toBeGreaterThan(initialHeight) }) it('does not render the line number gutter at all if the isLineNumberGutterVisible parameter is false', () => { - const {component, element, editor} = buildComponent({lineNumberGutterVisible: false}) + const { component, element, editor } = buildComponent({ + lineNumberGutterVisible: false + }) expect(element.querySelector('.line-number')).toBe(null) }) it('does not render the line numbers but still renders the line number gutter if showLineNumbers is false', async () => { function checkScrollContainerLeft (component) { - const {scrollContainer, gutterContainer} = component.refs - expect(scrollContainer.getBoundingClientRect().left).toBe(Math.round(gutterContainer.element.getBoundingClientRect().right)) + const { scrollContainer, gutterContainer } = component.refs + expect(scrollContainer.getBoundingClientRect().left).toBe( + Math.round(gutterContainer.element.getBoundingClientRect().right) + ) } - const {component, element, editor} = buildComponent({showLineNumbers: false}) - expect(Array.from(element.querySelectorAll('.line-number')).every((e) => e.textContent === '')).toBe(true) + const { component, element, editor } = buildComponent({ + showLineNumbers: false + }) + expect( + Array.from(element.querySelectorAll('.line-number')).every( + e => e.textContent === '' + ) + ).toBe(true) checkScrollContainerLeft(component) - await editor.update({showLineNumbers: true}) - expect(Array.from(element.querySelectorAll('.line-number')).map((e) => e.textContent)).toEqual([ - '00', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13' + await editor.update({ showLineNumbers: true }) + expect( + Array.from(element.querySelectorAll('.line-number')).map( + e => e.textContent + ) + ).toEqual([ + '00', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + '11', + '12', + '13' ]) checkScrollContainerLeft(component) - await editor.update({showLineNumbers: false}) - expect(Array.from(element.querySelectorAll('.line-number')).every((e) => e.textContent === '')).toBe(true) + await editor.update({ showLineNumbers: false }) + expect( + Array.from(element.querySelectorAll('.line-number')).every( + e => e.textContent === '' + ) + ).toBe(true) checkScrollContainerLeft(component) }) it('supports the placeholderText parameter', () => { const placeholderText = 'Placeholder Test' - const {element} = buildComponent({placeholderText, text: ''}) + const { element } = buildComponent({ placeholderText, text: '' }) expect(element.textContent).toContain(placeholderText) }) it('adds the data-grammar attribute and updates it when the grammar changes', async () => { await atom.packages.activatePackage('language-javascript') - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() expect(element.dataset.grammar).toBe('text plain null-grammar') atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.js') @@ -744,7 +928,7 @@ describe('TextEditorComponent', () => { }) it('adds the data-encoding attribute and updates it when the encoding changes', async () => { - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() expect(element.dataset.encoding).toBe('utf8') editor.setEncoding('ascii') @@ -753,61 +937,133 @@ describe('TextEditorComponent', () => { }) it('adds the has-selection class when the editor has a non-empty selection', async () => { - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() expect(element.classList.contains('has-selection')).toBe(false) - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[1, 0], [1, 10]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[1, 0], [1, 10]]]) await component.getNextUpdatePromise() expect(element.classList.contains('has-selection')).toBe(true) - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[1, 0], [1, 0]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[1, 0], [1, 0]]]) await component.getNextUpdatePromise() expect(element.classList.contains('has-selection')).toBe(false) }) it('assigns buffer-row and screen-row to each line number as data fields', async () => { - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() editor.setSoftWrapped(true) await component.getNextUpdatePromise() await setEditorWidthInCharacters(component, 40) { - const bufferRows = queryOnScreenLineNumberElements(element).map((e) => e.dataset.bufferRow) - const screenRows = queryOnScreenLineNumberElements(element).map((e) => e.dataset.screenRow) + const bufferRows = queryOnScreenLineNumberElements(element).map( + e => e.dataset.bufferRow + ) + const screenRows = queryOnScreenLineNumberElements(element).map( + e => e.dataset.screenRow + ) expect(bufferRows).toEqual([ - '0', '1', '2', '3', '3', '4', '5', '6', '6', '6', - '7', '8', '8', '8', '9', '10', '11', '11', '12' + '0', + '1', + '2', + '3', + '3', + '4', + '5', + '6', + '6', + '6', + '7', + '8', + '8', + '8', + '9', + '10', + '11', + '11', + '12' ]) expect(screenRows).toEqual([ - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '10', '11', '12', '13', '14', '15', '16', '17', '18' + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + '11', + '12', + '13', + '14', + '15', + '16', + '17', + '18' ]) } editor.getBuffer().insert([2, 0], '\n') await component.getNextUpdatePromise() { - const bufferRows = queryOnScreenLineNumberElements(element).map((e) => e.dataset.bufferRow) - const screenRows = queryOnScreenLineNumberElements(element).map((e) => e.dataset.screenRow) + const bufferRows = queryOnScreenLineNumberElements(element).map( + e => e.dataset.bufferRow + ) + const screenRows = queryOnScreenLineNumberElements(element).map( + e => e.dataset.screenRow + ) expect(bufferRows).toEqual([ - '0', '1', '2', '3', '4', '4', '5', '6', '7', '7', - '7', '8', '9', '9', '9', '10', '11', '12', '12', '13' + '0', + '1', + '2', + '3', + '4', + '4', + '5', + '6', + '7', + '7', + '7', + '8', + '9', + '9', + '9', + '10', + '11', + '12', + '12', + '13' ]) expect(screenRows).toEqual([ - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '10', '11', '12', '13', '14', '15', '16', '17', '18', '19' + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + '11', + '12', + '13', + '14', + '15', + '16', + '17', + '18', + '19' ]) } }) it('does not blow away class names added to the element by packages when changing the class name', async () => { assertDocumentFocused() - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() element.classList.add('a', 'b') expect(element.className).toBe('editor a b') element.focus() @@ -820,18 +1076,20 @@ describe('TextEditorComponent', () => { it('does not blow away class names managed by the component when packages change the element class name', async () => { assertDocumentFocused() - const {component, element, editor} = buildComponent({mini: true}) + const { component, element, editor } = buildComponent({ mini: true }) element.classList.add('a', 'b') element.focus() await component.getNextUpdatePromise() expect(element.className).toBe('editor mini a b is-focused') - element.className = 'a c d'; + element.className = 'a c d' await component.getNextUpdatePromise() expect(element.className).toBe('a c d editor is-focused mini') }) it('ignores resize events when the editor is hidden', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) + const { component, element, editor } = buildComponent({ + autoHeight: false + }) element.style.height = 5 * component.getLineHeight() + 'px' await component.getNextUpdatePromise() const originalClientContainerHeight = component.getClientContainerHeight() @@ -848,16 +1106,28 @@ describe('TextEditorComponent', () => { expect(component.visible).toBe(true) component.didResize() component.didResizeGutterContainer() - expect(component.getClientContainerHeight()).toBe(originalClientContainerHeight) - expect(component.getGutterContainerWidth()).toBe(originalGutterContainerWidth) - expect(component.getLineNumberGutterWidth()).toBe(originalLineNumberGutterWidth) + expect(component.getClientContainerHeight()).toBe( + originalClientContainerHeight + ) + expect(component.getGutterContainerWidth()).toBe( + originalGutterContainerWidth + ) + expect(component.getLineNumberGutterWidth()).toBe( + originalLineNumberGutterWidth + ) // Ensure measurements stay the same after receiving the intersection // observer events. await conditionPromise(() => !component.visible) - expect(component.getClientContainerHeight()).toBe(originalClientContainerHeight) - expect(component.getGutterContainerWidth()).toBe(originalGutterContainerWidth) - expect(component.getLineNumberGutterWidth()).toBe(originalLineNumberGutterWidth) + expect(component.getClientContainerHeight()).toBe( + originalClientContainerHeight + ) + expect(component.getGutterContainerWidth()).toBe( + originalGutterContainerWidth + ) + expect(component.getLineNumberGutterWidth()).toBe( + originalLineNumberGutterWidth + ) }) describe('randomized tests', () => { @@ -881,7 +1151,10 @@ describe('TextEditorComponent', () => { const random = Random(seed) const rowsPerTile = random.intBetween(1, 6) - const {component, element, editor} = buildComponent({rowsPerTile, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile, + autoHeight: false + }) editor.setSoftWrapped(Boolean(random(2))) await setEditorWidthInCharacters(component, random(20)) await setEditorHeightInLines(component, random(10)) @@ -918,20 +1191,35 @@ describe('TextEditorComponent', () => { } else if (k < 95) { editor.setSelectedBufferRange(range) } else { - if (random(2)) component.setScrollTop(random(component.getScrollHeight())) - if (random(2)) component.setScrollLeft(random(component.getScrollWidth())) + if (random(2)) + component.setScrollTop(random(component.getScrollHeight())) + if (random(2)) + component.setScrollLeft(random(component.getScrollWidth())) } component.scheduleUpdate() await component.getNextUpdatePromise() - const renderedLines = queryOnScreenLineElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) - const renderedLineNumbers = queryOnScreenLineNumberElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) + const renderedLines = queryOnScreenLineElements(element).sort( + (a, b) => a.dataset.screenRow - b.dataset.screenRow + ) + const renderedLineNumbers = queryOnScreenLineNumberElements( + element + ).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) const renderedStartRow = component.getRenderedStartRow() - const expectedLines = editor.displayLayer.getScreenLines(renderedStartRow, component.getRenderedEndRow()) + const expectedLines = editor.displayLayer.getScreenLines( + renderedStartRow, + component.getRenderedEndRow() + ) - expect(renderedLines.length).toBe(expectedLines.length, failureMessage) - expect(renderedLineNumbers.length).toBe(expectedLines.length, failureMessage) + expect(renderedLines.length).toBe( + expectedLines.length, + failureMessage + ) + expect(renderedLineNumbers.length).toBe( + expectedLines.length, + failureMessage + ) for (let k = 0; k < renderedLines.length; k++) { const expectedLine = expectedLines[k] const expectedText = expectedLine.lineText || ' ' @@ -942,12 +1230,21 @@ describe('TextEditorComponent', () => { // We append zero width NBSPs after folds at the end of the // line in order to support measurement. if (expectedText.endsWith(editor.displayLayer.foldCharacter)) { - renderedText = renderedText.substring(0, renderedText.length - 1) + renderedText = renderedText.substring( + 0, + renderedText.length - 1 + ) } expect(renderedText).toBe(expectedText, failureMessage) - expect(parseInt(renderedLine.dataset.screenRow)).toBe(renderedStartRow + k, failureMessage) - expect(parseInt(renderedLineNumber.dataset.screenRow)).toBe(renderedStartRow + k, failureMessage) + expect(parseInt(renderedLine.dataset.screenRow)).toBe( + renderedStartRow + k, + failureMessage + ) + expect(parseInt(renderedLineNumber.dataset.screenRow)).toBe( + renderedStartRow + k, + failureMessage + ) } } @@ -961,39 +1258,51 @@ describe('TextEditorComponent', () => { describe('mini editors', () => { it('adds the mini attribute and class even when the element is not attached', () => { { - const {element, editor} = buildComponent({mini: true}) + const { element, editor } = buildComponent({ mini: true }) expect(element.hasAttribute('mini')).toBe(true) expect(element.classList.contains('mini')).toBe(true) } { - const {element, editor} = buildComponent({mini: true, attach: false}) + const { element, editor } = buildComponent({ + mini: true, + attach: false + }) expect(element.hasAttribute('mini')).toBe(true) expect(element.classList.contains('mini')).toBe(true) } }) it('does not render the gutter container', () => { - const {component, element, editor} = buildComponent({mini: true}) + const { component, element, editor } = buildComponent({ mini: true }) expect(component.refs.gutterContainer).toBeUndefined() expect(element.querySelector('gutter-container')).toBeNull() }) it('does not render line decorations for the cursor line', async () => { - const {component, element, editor} = buildComponent({mini: true}) - expect(element.querySelector('.line').classList.contains('cursor-line')).toBe(false) + const { component, element, editor } = buildComponent({ mini: true }) + expect( + element.querySelector('.line').classList.contains('cursor-line') + ).toBe(false) - editor.update({mini: false}) + editor.update({ mini: false }) await component.getNextUpdatePromise() - expect(element.querySelector('.line').classList.contains('cursor-line')).toBe(true) + expect( + element.querySelector('.line').classList.contains('cursor-line') + ).toBe(true) - editor.update({mini: true}) + editor.update({ mini: true }) await component.getNextUpdatePromise() - expect(element.querySelector('.line').classList.contains('cursor-line')).toBe(false) + expect( + element.querySelector('.line').classList.contains('cursor-line') + ).toBe(false) }) it('does not render scrollbars', async () => { - const {component, element, editor} = buildComponent({mini: true, autoHeight: false}) + const { component, element, editor } = buildComponent({ + mini: true, + autoHeight: false + }) await setEditorWidthInCharacters(component, 10) editor.setText('x'.repeat(20) + 'y'.repeat(20)) @@ -1012,8 +1321,8 @@ describe('TextEditorComponent', () => { }) it('focuses the hidden input element and adds the is-focused class when focused', async () => { - const {component, element, editor} = buildComponent() - const {hiddenInput} = component.refs.cursorsAndInput.refs + const { component, element, editor } = buildComponent() + const { hiddenInput } = component.refs.cursorsAndInput.refs expect(document.activeElement).not.toBe(hiddenInput) element.focus() @@ -1032,8 +1341,8 @@ describe('TextEditorComponent', () => { }) it('updates the component when the hidden input is focused directly', async () => { - const {component, element, editor} = buildComponent() - const {hiddenInput} = component.refs.cursorsAndInput.refs + const { component, element, editor } = buildComponent() + const { hiddenInput } = component.refs.cursorsAndInput.refs expect(element.classList.contains('is-focused')).toBe(false) expect(document.activeElement).not.toBe(hiddenInput) @@ -1043,27 +1352,33 @@ describe('TextEditorComponent', () => { }) it('gracefully handles a focus event that occurs prior to the attachedCallback of the element', () => { - const {component, element, editor} = buildComponent({attach: false}) - const parent = document.createElement('text-editor-component-test-element') + const { component, element, editor } = buildComponent({ attach: false }) + const parent = document.createElement( + 'text-editor-component-test-element' + ) parent.appendChild(element) parent.didAttach = () => element.focus() jasmine.attachToDOM(parent) - expect(document.activeElement).toBe(component.refs.cursorsAndInput.refs.hiddenInput) + expect(document.activeElement).toBe( + component.refs.cursorsAndInput.refs.hiddenInput + ) }) it('gracefully handles a focus event that occurs prior to detecting the element has become visible', async () => { - const {component, element, editor} = buildComponent({attach: false}) + const { component, element, editor } = buildComponent({ attach: false }) element.style.display = 'none' jasmine.attachToDOM(element) element.style.display = 'block' element.focus() await component.getNextUpdatePromise() - expect(document.activeElement).toBe(component.refs.cursorsAndInput.refs.hiddenInput) + expect(document.activeElement).toBe( + component.refs.cursorsAndInput.refs.hiddenInput + ) }) it('emits blur events only when focus shifts to something other than the editor itself or its hidden input', () => { - const {element} = buildComponent() + const { element } = buildComponent() let blurEventCount = 0 element.addEventListener('blur', () => blurEventCount++) @@ -1079,20 +1394,29 @@ describe('TextEditorComponent', () => { describe('autoscroll', () => { it('automatically scrolls vertically when the requested range is within the vertical scroll margin of the top or bottom', async () => { - const {component, editor} = buildComponent({height: 120 + horizontalScrollbarHeight}) + const { component, editor } = buildComponent({ + height: 120 + horizontalScrollbarHeight + }) expect(component.getLastVisibleRow()).toBe(7) editor.scrollToScreenRange([[4, 0], [6, 0]]) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((6 + 1 + editor.verticalScrollMargin) * component.getLineHeight()) + expect(component.getScrollBottom()).toBe( + (6 + 1 + editor.verticalScrollMargin) * component.getLineHeight() + ) editor.scrollToScreenPosition([8, 0]) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((8 + 1 + editor.verticalScrollMargin) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (8 + 1 + editor.verticalScrollMargin) * + component.measurements.lineHeight + ) editor.scrollToScreenPosition([3, 0]) await component.getNextUpdatePromise() - expect(component.getScrollTop()).toBe((3 - editor.verticalScrollMargin) * component.measurements.lineHeight) + expect(component.getScrollTop()).toBe( + (3 - editor.verticalScrollMargin) * component.measurements.lineHeight + ) editor.scrollToScreenPosition([2, 0]) await component.getNextUpdatePromise() @@ -1100,47 +1424,64 @@ describe('TextEditorComponent', () => { }) it('does not vertically autoscroll by more than half of the visible lines if the editor is shorter than twice the scroll margin', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) - element.style.height = 5.5 * component.measurements.lineHeight + horizontalScrollbarHeight + 'px' + const { component, element, editor } = buildComponent({ + autoHeight: false + }) + element.style.height = + 5.5 * component.measurements.lineHeight + + horizontalScrollbarHeight + + 'px' await component.getNextUpdatePromise() expect(component.getLastVisibleRow()).toBe(5) const scrollMarginInLines = 2 editor.scrollToScreenPosition([6, 0]) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((6 + 1 + scrollMarginInLines) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (6 + 1 + scrollMarginInLines) * component.measurements.lineHeight + ) editor.scrollToScreenPosition([6, 4]) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((6 + 1 + scrollMarginInLines) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (6 + 1 + scrollMarginInLines) * component.measurements.lineHeight + ) editor.scrollToScreenRange([[4, 4], [6, 4]]) await component.getNextUpdatePromise() - expect(component.getScrollTop()).toBe((4 - scrollMarginInLines) * component.measurements.lineHeight) + expect(component.getScrollTop()).toBe( + (4 - scrollMarginInLines) * component.measurements.lineHeight + ) - editor.scrollToScreenRange([[4, 4], [6, 4]], {reversed: false}) + editor.scrollToScreenRange([[4, 4], [6, 4]], { reversed: false }) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((6 + 1 + scrollMarginInLines) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (6 + 1 + scrollMarginInLines) * component.measurements.lineHeight + ) }) it('autoscrolls the given range to the center of the screen if the `center` option is true', async () => { - const {component, editor} = buildComponent({height: 50}) + const { component, editor } = buildComponent({ height: 50 }) expect(component.getLastVisibleRow()).toBe(2) - editor.scrollToScreenRange([[4, 0], [6, 0]], {center: true}) + editor.scrollToScreenRange([[4, 0], [6, 0]], { center: true }) await component.getNextUpdatePromise() - const actualScrollCenter = (component.getScrollTop() + component.getScrollBottom()) / 2 - const expectedScrollCenter = (4 + 7) / 2 * component.getLineHeight() + const actualScrollCenter = + (component.getScrollTop() + component.getScrollBottom()) / 2 + const expectedScrollCenter = ((4 + 7) / 2) * component.getLineHeight() expect(actualScrollCenter).toBeCloseTo(expectedScrollCenter, 0) }) it('automatically scrolls horizontally when the requested range is within the horizontal scroll margin of the right edge of the gutter or right edge of the scroll container', async () => { - const {component, element, editor} = buildComponent() - const {scrollContainer} = component.refs + const { component, element, editor } = buildComponent() + const { scrollContainer } = component.refs element.style.width = component.getGutterContainerWidth() + - 3 * editor.horizontalScrollMargin * component.measurements.baseCharacterWidth + 'px' + 3 * + editor.horizontalScrollMargin * + component.measurements.baseCharacterWidth + + 'px' await component.getNextUpdatePromise() editor.scrollToScreenRange([[1, 12], [2, 28]]) @@ -1148,59 +1489,78 @@ describe('TextEditorComponent', () => { let expectedScrollLeft = clientLeftForCharacter(component, 1, 12) - lineNodeForScreenRow(component, 1).getBoundingClientRect().left - - (editor.horizontalScrollMargin * component.measurements.baseCharacterWidth) + editor.horizontalScrollMargin * + component.measurements.baseCharacterWidth expect(component.getScrollLeft()).toBeCloseTo(expectedScrollLeft, 0) - editor.scrollToScreenRange([[1, 12], [2, 28]], {reversed: false}) + editor.scrollToScreenRange([[1, 12], [2, 28]], { reversed: false }) await component.getNextUpdatePromise() expectedScrollLeft = component.getGutterContainerWidth() + clientLeftForCharacter(component, 2, 28) - lineNodeForScreenRow(component, 2).getBoundingClientRect().left + - (editor.horizontalScrollMargin * component.measurements.baseCharacterWidth) - + editor.horizontalScrollMargin * + component.measurements.baseCharacterWidth - component.getScrollContainerClientWidth() expect(component.getScrollLeft()).toBeCloseTo(expectedScrollLeft, 0) }) it('does not horizontally autoscroll by more than half of the visible "base-width" characters if the editor is narrower than twice the scroll margin', async () => { - const {component, editor} = buildComponent({autoHeight: false}) - await setEditorWidthInCharacters(component, 1.5 * editor.horizontalScrollMargin) - const editorWidthInChars = component.getScrollContainerClientWidth() / component.getBaseCharacterWidth() + const { component, editor } = buildComponent({ autoHeight: false }) + await setEditorWidthInCharacters( + component, + 1.5 * editor.horizontalScrollMargin + ) + const editorWidthInChars = + component.getScrollContainerClientWidth() / + component.getBaseCharacterWidth() expect(Math.round(editorWidthInChars)).toBe(9) editor.scrollToScreenRange([[6, 10], [6, 15]]) await component.getNextUpdatePromise() let expectedScrollLeft = Math.floor( clientLeftForCharacter(component, 6, 10) - - lineNodeForScreenRow(component, 1).getBoundingClientRect().left - - Math.floor((editorWidthInChars - 1) / 2) * component.getBaseCharacterWidth() + lineNodeForScreenRow(component, 1).getBoundingClientRect().left - + Math.floor((editorWidthInChars - 1) / 2) * + component.getBaseCharacterWidth() ) expect(component.getScrollLeft()).toBe(expectedScrollLeft) }) it('correctly autoscrolls after inserting a line that exceeds the current content width', async () => { - const {component, element, editor} = buildComponent() - element.style.width = component.getGutterContainerWidth() + component.getContentWidth() + 'px' + const { component, element, editor } = buildComponent() + element.style.width = + component.getGutterContainerWidth() + component.getContentWidth() + 'px' await component.getNextUpdatePromise() editor.setCursorScreenPosition([0, Infinity]) editor.insertText('x'.repeat(100)) await component.getNextUpdatePromise() - expect(component.getScrollLeft()).toBe(component.getScrollWidth() - component.getScrollContainerClientWidth()) + expect(component.getScrollLeft()).toBe( + component.getScrollWidth() - component.getScrollContainerClientWidth() + ) }) it('does not try to measure lines that do not exist when the animation frame is delivered', async () => { - const {component, editor} = buildComponent({autoHeight: false, height: 30, rowsPerTile: 2}) + const { component, editor } = buildComponent({ + autoHeight: false, + height: 30, + rowsPerTile: 2 + }) editor.scrollToBufferPosition([11, 5]) editor.getBuffer().deleteRows(11, 12) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((10 + 1) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (10 + 1) * component.measurements.lineHeight + ) }) it('accounts for the presence of horizontal scrollbars that appear during the same frame as the autoscroll', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) - const {scrollContainer} = component.refs + const { component, element, editor } = buildComponent({ + autoHeight: false + }) + const { scrollContainer } = component.refs element.style.height = component.getContentHeight() / 2 + 'px' element.style.width = component.getScrollWidth() + 'px' await component.getNextUpdatePromise() @@ -1209,8 +1569,12 @@ describe('TextEditorComponent', () => { editor.insertText('\n\n' + 'x'.repeat(100)) await component.getNextUpdatePromise() - expect(component.getScrollTop()).toBe(component.getScrollHeight() - component.getScrollContainerClientHeight()) - expect(component.getScrollLeft()).toBe(component.getScrollWidth() - component.getScrollContainerClientWidth()) + expect(component.getScrollTop()).toBe( + component.getScrollHeight() - component.getScrollContainerClientHeight() + ) + expect(component.getScrollLeft()).toBe( + component.getScrollWidth() - component.getScrollContainerClientWidth() + ) // Scrolling to the top should not throw an error. This failed // previously due to horizontalPositionsToMeasure not being empty after @@ -1223,7 +1587,10 @@ describe('TextEditorComponent', () => { describe('logical scroll positions', () => { it('allows the scrollTop to be changed and queried in terms of rows via setScrollTopRow and getScrollTopRow', () => { - const {component, element, editor} = buildComponent({attach: false, height: 80}) + const { component, element, editor } = buildComponent({ + attach: false, + height: 80 + }) // Caches the scrollTopRow if we don't have measurements component.setScrollTopRow(6) @@ -1234,30 +1601,43 @@ describe('TextEditorComponent', () => { const expectedScrollTop = Math.round(6 * component.getLineHeight()) expect(component.getScrollTopRow()).toBe(6) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) // Allows the scrollTopRow to be updated while attached component.setScrollTopRow(4) expect(component.getScrollTopRow()).toBe(4) - expect(component.getScrollTop()).toBe(Math.round(4 * component.getLineHeight())) + expect(component.getScrollTop()).toBe( + Math.round(4 * component.getLineHeight()) + ) // Preserves the scrollTopRow when detached element.remove() expect(component.getScrollTopRow()).toBe(4) - expect(component.getScrollTop()).toBe(Math.round(4 * component.getLineHeight())) + expect(component.getScrollTop()).toBe( + Math.round(4 * component.getLineHeight()) + ) component.setScrollTopRow(6) expect(component.getScrollTopRow()).toBe(6) - expect(component.getScrollTop()).toBe(Math.round(6 * component.getLineHeight())) + expect(component.getScrollTop()).toBe( + Math.round(6 * component.getLineHeight()) + ) jasmine.attachToDOM(element) element.style.height = '60px' expect(component.getScrollTopRow()).toBe(6) - expect(component.getScrollTop()).toBe(Math.round(6 * component.getLineHeight())) + expect(component.getScrollTop()).toBe( + Math.round(6 * component.getLineHeight()) + ) }) it('allows the scrollLeft to be changed and queried in terms of base character columns via setScrollLeftColumn and getScrollLeftColumn', () => { - const {component, element} = buildComponent({attach: false, width: 80}) + const { component, element } = buildComponent({ + attach: false, + width: 80 + }) // Caches the scrollTopRow if we don't have measurements component.setScrollLeftColumn(2) @@ -1265,143 +1645,218 @@ describe('TextEditorComponent', () => { // Assigns the scrollTop based on the logical position when attached jasmine.attachToDOM(element) - expect(component.getScrollLeft()).toBeCloseTo(2 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 2 * component.getBaseCharacterWidth(), + 0 + ) // Allows the scrollTopRow to be updated while attached component.setScrollLeftColumn(4) - expect(component.getScrollLeft()).toBeCloseTo(4 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 4 * component.getBaseCharacterWidth(), + 0 + ) // Preserves the scrollTopRow when detached element.remove() - expect(component.getScrollLeft()).toBeCloseTo(4 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 4 * component.getBaseCharacterWidth(), + 0 + ) component.setScrollLeftColumn(6) - expect(component.getScrollLeft()).toBeCloseTo(6 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 6 * component.getBaseCharacterWidth(), + 0 + ) jasmine.attachToDOM(element) element.style.width = '60px' - expect(component.getScrollLeft()).toBeCloseTo(6 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 6 * component.getBaseCharacterWidth(), + 0 + ) }) }) describe('scrolling via the mouse wheel', () => { it('scrolls vertically or horizontally depending on whether deltaX or deltaY is larger', () => { const scrollSensitivity = 30 - const {component, editor} = buildComponent({height: 50, width: 50, scrollSensitivity}) + const { component, editor } = buildComponent({ + height: 50, + width: 50, + scrollSensitivity + }) { const expectedScrollTop = 20 * (scrollSensitivity / 100) const expectedScrollLeft = component.getScrollLeft() - component.didMouseWheel({wheelDeltaX: -5, wheelDeltaY: -20}) + component.didMouseWheel({ wheelDeltaX: -5, wheelDeltaY: -20 }) expect(component.getScrollTop()).toBe(expectedScrollTop) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)` + ) } { - const expectedScrollTop = component.getScrollTop() - (10 * (scrollSensitivity / 100)) + const expectedScrollTop = + component.getScrollTop() - 10 * (scrollSensitivity / 100) const expectedScrollLeft = component.getScrollLeft() - component.didMouseWheel({wheelDeltaX: -5, wheelDeltaY: 10}) + component.didMouseWheel({ wheelDeltaX: -5, wheelDeltaY: 10 }) expect(component.getScrollTop()).toBe(expectedScrollTop) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)` + ) } { const expectedScrollTop = component.getScrollTop() const expectedScrollLeft = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: -20, wheelDeltaY: 10}) + component.didMouseWheel({ wheelDeltaX: -20, wheelDeltaY: 10 }) expect(component.getScrollTop()).toBe(expectedScrollTop) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)` + ) } { const expectedScrollTop = component.getScrollTop() - const expectedScrollLeft = component.getScrollLeft() - (10 * (scrollSensitivity / 100)) - component.didMouseWheel({wheelDeltaX: 10, wheelDeltaY: -8}) + const expectedScrollLeft = + component.getScrollLeft() - 10 * (scrollSensitivity / 100) + component.didMouseWheel({ wheelDeltaX: 10, wheelDeltaY: -8 }) expect(component.getScrollTop()).toBe(expectedScrollTop) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)` + ) } }) it('inverts deltaX and deltaY when holding shift on Windows and Linux', async () => { const scrollSensitivity = 50 - const {component, editor} = buildComponent({height: 50, width: 50, scrollSensitivity}) + const { component, editor } = buildComponent({ + height: 50, + width: 50, + scrollSensitivity + }) component.props.platform = 'linux' { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20}) + component.didMouseWheel({ wheelDeltaX: 0, wheelDeltaY: -20 }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } { const expectedScrollLeft = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: 0, + wheelDeltaY: -20, + shiftKey: true + }) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(-${expectedScrollLeft}px, 0px)`) + expect(component.refs.content.style.transform).toBe( + `translate(-${expectedScrollLeft}px, 0px)` + ) await setScrollLeft(component, 0) } { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: -20, wheelDeltaY: 0, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: -20, + wheelDeltaY: 0, + shiftKey: true + }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } component.props.platform = 'win32' { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20}) + component.didMouseWheel({ wheelDeltaX: 0, wheelDeltaY: -20 }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } { const expectedScrollLeft = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: 0, + wheelDeltaY: -20, + shiftKey: true + }) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(-${expectedScrollLeft}px, 0px)`) + expect(component.refs.content.style.transform).toBe( + `translate(-${expectedScrollLeft}px, 0px)` + ) await setScrollLeft(component, 0) } { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: -20, wheelDeltaY: 0, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: -20, + wheelDeltaY: 0, + shiftKey: true + }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } component.props.platform = 'darwin' { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20}) + component.didMouseWheel({ wheelDeltaX: 0, wheelDeltaY: -20 }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: 0, + wheelDeltaY: -20, + shiftKey: true + }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } { const expectedScrollLeft = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: -20, wheelDeltaY: 0, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: -20, + wheelDeltaY: 0, + shiftKey: true + }) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(-${expectedScrollLeft}px, 0px)`) + expect(component.refs.content.style.transform).toBe( + `translate(-${expectedScrollLeft}px, 0px)` + ) await setScrollLeft(component, 0) } }) @@ -1409,12 +1864,17 @@ describe('TextEditorComponent', () => { describe('scrolling via the API', () => { it('ignores scroll requests to NaN, null or undefined positions', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 3) await setEditorWidthInCharacters(component, 10) const initialScrollTop = Math.round(2 * component.getLineHeight()) - const initialScrollLeft = Math.round(5 * component.getBaseCharacterWidth()) + const initialScrollLeft = Math.round( + 5 * component.getBaseCharacterWidth() + ) setScrollTop(component, initialScrollTop) setScrollLeft(component, initialScrollLeft) await component.getNextUpdatePromise() @@ -1441,7 +1901,9 @@ describe('TextEditorComponent', () => { describe('line and line number decorations', () => { it('adds decoration classes on screen lines spanned by decorated markers', async () => { - const {component, element, editor} = buildComponent({softWrapped: true}) + const { component, element, editor } = buildComponent({ + softWrapped: true + }) await setEditorWidthInCharacters(component, 55) expect(lineNodeForScreenRow(component, 3).textContent).toBe( ' var pivot = items.shift(), current, left = [], ' @@ -1455,141 +1917,311 @@ describe('TextEditorComponent', () => { const marker2 = layer.markScreenPosition([5, 0]) const marker3 = layer.markScreenPosition([8, 0]) const marker4 = layer.markScreenPosition([10, 0]) - const markerDecoration = editor.decorateMarker(marker1, {type: ['line', 'line-number'], class: 'a'}) - const layerDecoration = editor.decorateMarkerLayer(layer, {type: ['line', 'line-number'], class: 'b'}) - layerDecoration.setPropertiesForMarker(marker4, {type: 'line', class: 'c'}) + const markerDecoration = editor.decorateMarker(marker1, { + type: ['line', 'line-number'], + class: 'a' + }) + const layerDecoration = editor.decorateMarkerLayer(layer, { + type: ['line', 'line-number'], + class: 'b' + }) + layerDecoration.setPropertiesForMarker(marker4, { + type: 'line', + class: 'c' + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 4).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 5).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 8).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 10).classList.contains('b')).toBe(false) - expect(lineNodeForScreenRow(component, 10).classList.contains('c')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 4).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 5).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 8).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 10).classList.contains('b')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 10).classList.contains('c')).toBe( + true + ) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 3).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 4).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 5).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 8).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 10).classList.contains('b')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 10).classList.contains('c')).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 3).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 4).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 5).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 8).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 10).classList.contains('b') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 10).classList.contains('c') + ).toBe(false) marker1.setScreenRange([[5, 0], [8, 0]]) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 4).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 5).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 5).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 6).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 7).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 8).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 8).classList.contains('b')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 4).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 5).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 5).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 6).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 7).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 8).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 8).classList.contains('b')).toBe( + true + ) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 3).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 4).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 5).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 5).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 6).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 7).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 8).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 8).classList.contains('b')).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 3).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 4).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 5).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 5).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 6).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 7).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 8).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 8).classList.contains('b') + ).toBe(true) }) it('honors the onlyEmpty and onlyNonEmpty decoration options', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenPosition([1, 0]) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'a', onlyEmpty: true}) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'b', onlyNonEmpty: true}) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'c'}) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'a', + onlyEmpty: true + }) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'b', + onlyNonEmpty: true + }) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'c' + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe(false) - expect(lineNodeForScreenRow(component, 1).classList.contains('c')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('b')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('c')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 1).classList.contains('c')).toBe( + true + ) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('b') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('c') + ).toBe(true) marker.setScreenRange([[1, 0], [2, 4]]) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 1).classList.contains('c')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('c')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('c')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('c')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 1).classList.contains('c')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('c')).toBe( + true + ) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('c') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('c') + ).toBe(true) }) it('honors the onlyHead option', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenRange([[1, 4], [3, 4]]) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'a', onlyHead: true}) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'a', + onlyHead: true + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 3).classList.contains('a')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe( + true + ) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 3).classList.contains('a') + ).toBe(true) }) it('only decorates the last row of non-empty ranges that end at column 0 if omitEmptyLastRow is false', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenRange([[1, 0], [3, 0]]) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'a'}) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'b', omitEmptyLastRow: false}) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'a' + }) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'b', + omitEmptyLastRow: false + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe(false) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe( + false + ) - expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 3).classList.contains('b')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('b')).toBe( + true + ) }) it('does not decorate invalidated markers', async () => { - const {component, element, editor} = buildComponent() - const marker = editor.markScreenRange([[1, 0], [3, 0]], {invalidate: 'touch'}) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'a'}) + const { component, element, editor } = buildComponent() + const marker = editor.markScreenRange([[1, 0], [3, 0]], { + invalidate: 'touch' + }) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'a' + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(true) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + true + ) editor.getBuffer().insert([2, 0], 'x') expect(marker.isValid()).toBe(false) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(false) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + false + ) }) }) describe('highlight decorations', () => { it('renders single-line highlights', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenRange([[1, 2], [1, 10]]) - editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + editor.decorateMarker(marker, { type: 'highlight', class: 'a' }) await component.getNextUpdatePromise() { const regions = element.querySelectorAll('.highlight.a .region.a') expect(regions.length).toBe(1) const regionRect = regions[0].getBoundingClientRect() - expect(regionRect.top).toBe(lineNodeForScreenRow(component, 1).getBoundingClientRect().top) - expect(Math.round(regionRect.left)).toBe(clientLeftForCharacter(component, 1, 2)) - expect(Math.round(regionRect.right)).toBe(clientLeftForCharacter(component, 1, 10)) + expect(regionRect.top).toBe( + lineNodeForScreenRow(component, 1).getBoundingClientRect().top + ) + expect(Math.round(regionRect.left)).toBe( + clientLeftForCharacter(component, 1, 2) + ) + expect(Math.round(regionRect.right)).toBe( + clientLeftForCharacter(component, 1, 10) + ) } marker.setScreenRange([[1, 4], [1, 8]]) @@ -1599,17 +2231,25 @@ describe('TextEditorComponent', () => { const regions = element.querySelectorAll('.highlight.a .region.a') expect(regions.length).toBe(1) const regionRect = regions[0].getBoundingClientRect() - expect(regionRect.top).toBe(lineNodeForScreenRow(component, 1).getBoundingClientRect().top) - expect(regionRect.bottom).toBe(lineNodeForScreenRow(component, 1).getBoundingClientRect().bottom) - expect(Math.round(regionRect.left)).toBe(clientLeftForCharacter(component, 1, 4)) - expect(Math.round(regionRect.right)).toBe(clientLeftForCharacter(component, 1, 8)) + expect(regionRect.top).toBe( + lineNodeForScreenRow(component, 1).getBoundingClientRect().top + ) + expect(regionRect.bottom).toBe( + lineNodeForScreenRow(component, 1).getBoundingClientRect().bottom + ) + expect(Math.round(regionRect.left)).toBe( + clientLeftForCharacter(component, 1, 4) + ) + expect(Math.round(regionRect.right)).toBe( + clientLeftForCharacter(component, 1, 8) + ) } }) it('renders multi-line highlights', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3}) + const { component, element, editor } = buildComponent({ rowsPerTile: 3 }) const marker = editor.markScreenRange([[2, 4], [3, 4]]) - editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + editor.decorateMarker(marker, { type: 'highlight', class: 'a' }) await component.getNextUpdatePromise() @@ -1619,16 +2259,32 @@ describe('TextEditorComponent', () => { const regions = element.querySelectorAll('.highlight.a .region.a') expect(regions.length).toBe(2) const region0Rect = regions[0].getBoundingClientRect() - expect(region0Rect.top).toBe(lineNodeForScreenRow(component, 2).getBoundingClientRect().top) - expect(region0Rect.bottom).toBe(lineNodeForScreenRow(component, 2).getBoundingClientRect().bottom) - expect(Math.round(region0Rect.left)).toBe(clientLeftForCharacter(component, 2, 4)) - expect(Math.round(region0Rect.right)).toBe(component.refs.content.getBoundingClientRect().right) + expect(region0Rect.top).toBe( + lineNodeForScreenRow(component, 2).getBoundingClientRect().top + ) + expect(region0Rect.bottom).toBe( + lineNodeForScreenRow(component, 2).getBoundingClientRect().bottom + ) + expect(Math.round(region0Rect.left)).toBe( + clientLeftForCharacter(component, 2, 4) + ) + expect(Math.round(region0Rect.right)).toBe( + component.refs.content.getBoundingClientRect().right + ) const region1Rect = regions[1].getBoundingClientRect() - expect(region1Rect.top).toBe(lineNodeForScreenRow(component, 3).getBoundingClientRect().top) - expect(region1Rect.bottom).toBe(lineNodeForScreenRow(component, 3).getBoundingClientRect().bottom) - expect(Math.round(region1Rect.left)).toBe(clientLeftForCharacter(component, 3, 0)) - expect(Math.round(region1Rect.right)).toBe(clientLeftForCharacter(component, 3, 4)) + expect(region1Rect.top).toBe( + lineNodeForScreenRow(component, 3).getBoundingClientRect().top + ) + expect(region1Rect.bottom).toBe( + lineNodeForScreenRow(component, 3).getBoundingClientRect().bottom + ) + expect(Math.round(region1Rect.left)).toBe( + clientLeftForCharacter(component, 3, 0) + ) + expect(Math.round(region1Rect.right)).toBe( + clientLeftForCharacter(component, 3, 4) + ) } marker.setScreenRange([[2, 4], [5, 4]]) @@ -1641,29 +2297,59 @@ describe('TextEditorComponent', () => { expect(regions.length).toBe(3) const region0Rect = regions[0].getBoundingClientRect() - expect(region0Rect.top).toBe(lineNodeForScreenRow(component, 2).getBoundingClientRect().top) - expect(region0Rect.bottom).toBe(lineNodeForScreenRow(component, 2).getBoundingClientRect().bottom) - expect(Math.round(region0Rect.left)).toBe(clientLeftForCharacter(component, 2, 4)) - expect(Math.round(region0Rect.right)).toBe(component.refs.content.getBoundingClientRect().right) + expect(region0Rect.top).toBe( + lineNodeForScreenRow(component, 2).getBoundingClientRect().top + ) + expect(region0Rect.bottom).toBe( + lineNodeForScreenRow(component, 2).getBoundingClientRect().bottom + ) + expect(Math.round(region0Rect.left)).toBe( + clientLeftForCharacter(component, 2, 4) + ) + expect(Math.round(region0Rect.right)).toBe( + component.refs.content.getBoundingClientRect().right + ) const region1Rect = regions[1].getBoundingClientRect() - expect(region1Rect.top).toBe(lineNodeForScreenRow(component, 3).getBoundingClientRect().top) - expect(region1Rect.bottom).toBe(lineNodeForScreenRow(component, 5).getBoundingClientRect().top) - expect(Math.round(region1Rect.left)).toBe(component.refs.content.getBoundingClientRect().left) - expect(Math.round(region1Rect.right)).toBe(component.refs.content.getBoundingClientRect().right) + expect(region1Rect.top).toBe( + lineNodeForScreenRow(component, 3).getBoundingClientRect().top + ) + expect(region1Rect.bottom).toBe( + lineNodeForScreenRow(component, 5).getBoundingClientRect().top + ) + expect(Math.round(region1Rect.left)).toBe( + component.refs.content.getBoundingClientRect().left + ) + expect(Math.round(region1Rect.right)).toBe( + component.refs.content.getBoundingClientRect().right + ) const region2Rect = regions[2].getBoundingClientRect() - expect(region2Rect.top).toBe(lineNodeForScreenRow(component, 5).getBoundingClientRect().top) - expect(region2Rect.bottom).toBe(lineNodeForScreenRow(component, 6).getBoundingClientRect().top) - expect(Math.round(region2Rect.left)).toBe(component.refs.content.getBoundingClientRect().left) - expect(Math.round(region2Rect.right)).toBe(clientLeftForCharacter(component, 5, 4)) + expect(region2Rect.top).toBe( + lineNodeForScreenRow(component, 5).getBoundingClientRect().top + ) + expect(region2Rect.bottom).toBe( + lineNodeForScreenRow(component, 6).getBoundingClientRect().top + ) + expect(Math.round(region2Rect.left)).toBe( + component.refs.content.getBoundingClientRect().left + ) + expect(Math.round(region2Rect.right)).toBe( + clientLeftForCharacter(component, 5, 4) + ) } }) it('can flash highlight decorations', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, height: 200}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + height: 200 + }) const marker = editor.markScreenRange([[2, 4], [3, 4]]) - const decoration = editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + const decoration = editor.decorateMarker(marker, { + type: 'highlight', + class: 'a' + }) decoration.flash('b', 10) // Flash on initial appearance of highlight @@ -1695,9 +2381,15 @@ describe('TextEditorComponent', () => { }) it("flashing a highlight decoration doesn't unflash other highlight decorations", async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, height: 200}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + height: 200 + }) const marker = editor.markScreenRange([[2, 4], [3, 4]]) - const decoration = editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + const decoration = editor.decorateMarker(marker, { + type: 'highlight', + class: 'a' + }) // Flash one class decoration.flash('c', 1000) @@ -1714,34 +2406,46 @@ describe('TextEditorComponent', () => { }) it('supports layer decorations', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 12}) + const { component, element, editor } = buildComponent({ rowsPerTile: 12 }) const markerLayer = editor.addMarkerLayer() const marker1 = markerLayer.markScreenRange([[2, 4], [3, 4]]) const marker2 = markerLayer.markScreenRange([[5, 6], [7, 8]]) - const decoration = editor.decorateMarkerLayer(markerLayer, {type: 'highlight', class: 'a'}) + const decoration = editor.decorateMarkerLayer(markerLayer, { + type: 'highlight', + class: 'a' + }) await component.getNextUpdatePromise() const highlights = element.querySelectorAll('.highlight') expect(highlights[0].classList.contains('a')).toBe(true) expect(highlights[1].classList.contains('a')).toBe(true) - decoration.setPropertiesForMarker(marker1, {type: 'highlight', class: 'b'}) + decoration.setPropertiesForMarker(marker1, { + type: 'highlight', + class: 'b' + }) await component.getNextUpdatePromise() expect(highlights[0].classList.contains('b')).toBe(true) expect(highlights[1].classList.contains('a')).toBe(true) decoration.setPropertiesForMarker(marker1, null) - decoration.setPropertiesForMarker(marker2, {type: 'highlight', class: 'c'}) + decoration.setPropertiesForMarker(marker2, { + type: 'highlight', + class: 'c' + }) await component.getNextUpdatePromise() expect(highlights[0].classList.contains('a')).toBe(true) expect(highlights[1].classList.contains('c')).toBe(true) }) it('clears highlights when recycling a tile that previously contained highlights and now does not', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 2) const marker = editor.markScreenRange([[1, 2], [1, 10]]) - editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + editor.decorateMarker(marker, { type: 'highlight', class: 'a' }) await component.getNextUpdatePromise() expect(element.querySelectorAll('.highlight.a').length).toBe(1) @@ -1751,43 +2455,56 @@ describe('TextEditorComponent', () => { }) it('does not move existing highlights when adding or removing other highlight decorations (regression)', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker1 = editor.markScreenRange([[1, 6], [1, 10]]) - editor.decorateMarker(marker1, {type: 'highlight', class: 'a'}) + editor.decorateMarker(marker1, { type: 'highlight', class: 'a' }) await component.getNextUpdatePromise() const marker1Region = element.querySelector('.highlight.a') - expect(Array.from(marker1Region.parentElement.children).indexOf(marker1Region)).toBe(0) + expect( + Array.from(marker1Region.parentElement.children).indexOf(marker1Region) + ).toBe(0) const marker2 = editor.markScreenRange([[1, 2], [1, 4]]) - editor.decorateMarker(marker2, {type: 'highlight', class: 'b'}) + editor.decorateMarker(marker2, { type: 'highlight', class: 'b' }) await component.getNextUpdatePromise() const marker2Region = element.querySelector('.highlight.b') - expect(Array.from(marker1Region.parentElement.children).indexOf(marker1Region)).toBe(0) - expect(Array.from(marker2Region.parentElement.children).indexOf(marker2Region)).toBe(1) + expect( + Array.from(marker1Region.parentElement.children).indexOf(marker1Region) + ).toBe(0) + expect( + Array.from(marker2Region.parentElement.children).indexOf(marker2Region) + ).toBe(1) marker2.destroy() await component.getNextUpdatePromise() - expect(Array.from(marker1Region.parentElement.children).indexOf(marker1Region)).toBe(0) + expect( + Array.from(marker1Region.parentElement.children).indexOf(marker1Region) + ).toBe(0) }) it('correctly positions highlights that end on rows preceding or following block decorations', async () => { - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() const item1 = document.createElement('div') item1.style.height = '30px' item1.style.backgroundColor = 'blue' editor.decorateMarker(editor.markBufferPosition([4, 0]), { - type: 'block', position: 'after', item: item1 + type: 'block', + position: 'after', + item: item1 }) const item2 = document.createElement('div') item2.style.height = '30px' item2.style.backgroundColor = 'yellow' editor.decorateMarker(editor.markBufferPosition([4, 0]), { - type: 'block', position: 'before', item: item2 + type: 'block', + position: 'before', + item: item2 }) editor.decorateMarker(editor.markBufferRange([[3, 0], [4, Infinity]]), { - type: 'highlight', class: 'highlight' + type: 'highlight', + class: 'highlight' }) await component.getNextUpdatePromise() @@ -1806,13 +2523,21 @@ describe('TextEditorComponent', () => { fakeWindow.style.backgroundColor = 'blue' fakeWindow.appendChild(component.element) jasmine.attachToDOM(fakeWindow) - spyOn(component, 'getWindowInnerWidth').andCallFake(() => fakeWindow.getBoundingClientRect().width) - spyOn(component, 'getWindowInnerHeight').andCallFake(() => fakeWindow.getBoundingClientRect().height) + spyOn(component, 'getWindowInnerWidth').andCallFake( + () => fakeWindow.getBoundingClientRect().width + ) + spyOn(component, 'getWindowInnerHeight').andCallFake( + () => fakeWindow.getBoundingClientRect().height + ) return fakeWindow } it('renders overlay elements at the specified screen position unless it would overflow the window', async () => { - const {component, element, editor} = buildComponent({width: 200, height: 100, attach: false}) + const { component, element, editor } = buildComponent({ + width: 200, + height: 100, + attach: false + }) const fakeWindow = attachFakeWindow(component) await setScrollTop(component, 50) @@ -1826,62 +2551,94 @@ describe('TextEditorComponent', () => { overlayElement.style.margin = '3px' overlayElement.style.backgroundColor = 'red' - const decoration = editor.decorateMarker(marker, {type: 'overlay', item: overlayElement, class: 'a'}) + const decoration = editor.decorateMarker(marker, { + type: 'overlay', + item: overlayElement, + class: 'a' + }) await component.getNextUpdatePromise() const overlayComponent = component.overlayComponents.values().next().value const overlayWrapper = overlayElement.parentElement expect(overlayWrapper.classList.contains('a')).toBe(true) - expect(overlayWrapper.getBoundingClientRect().top).toBe(clientTopForLine(component, 5)) - expect(overlayWrapper.getBoundingClientRect().left).toBe(clientLeftForCharacter(component, 4, 25)) + expect(overlayWrapper.getBoundingClientRect().top).toBe( + clientTopForLine(component, 5) + ) + expect(overlayWrapper.getBoundingClientRect().left).toBe( + clientLeftForCharacter(component, 4, 25) + ) // Updates the horizontal position on scroll await setScrollLeft(component, 150) - expect(overlayWrapper.getBoundingClientRect().left).toBe(clientLeftForCharacter(component, 4, 25)) + expect(overlayWrapper.getBoundingClientRect().left).toBe( + clientLeftForCharacter(component, 4, 25) + ) // Shifts the overlay horizontally to ensure the overlay element does not // overflow the window await setScrollLeft(component, 30) - expect(overlayElement.getBoundingClientRect().right).toBe(fakeWindow.getBoundingClientRect().right) + expect(overlayElement.getBoundingClientRect().right).toBe( + fakeWindow.getBoundingClientRect().right + ) await setScrollLeft(component, 280) - expect(overlayElement.getBoundingClientRect().left).toBe(fakeWindow.getBoundingClientRect().left) + expect(overlayElement.getBoundingClientRect().left).toBe( + fakeWindow.getBoundingClientRect().left + ) // Updates the vertical position on scroll await setScrollTop(component, 60) - expect(overlayWrapper.getBoundingClientRect().top).toBe(clientTopForLine(component, 5)) + expect(overlayWrapper.getBoundingClientRect().top).toBe( + clientTopForLine(component, 5) + ) // Flips the overlay vertically to ensure the overlay element does not // overflow the bottom of the window setScrollLeft(component, 100) await setScrollTop(component, 0) - expect(overlayWrapper.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 4)) + expect(overlayWrapper.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 4) + ) // Flips the overlay vertically on overlay resize if necessary await setScrollTop(component, 20) - expect(overlayWrapper.getBoundingClientRect().top).toBe(clientTopForLine(component, 5)) + expect(overlayWrapper.getBoundingClientRect().top).toBe( + clientTopForLine(component, 5) + ) overlayElement.style.height = 60 + 'px' await overlayComponent.getNextUpdatePromise() - expect(overlayWrapper.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 4)) + expect(overlayWrapper.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 4) + ) // Does not flip the overlay vertically if it would overflow the top of the window overlayElement.style.height = 80 + 'px' await overlayComponent.getNextUpdatePromise() - expect(overlayWrapper.getBoundingClientRect().top).toBe(clientTopForLine(component, 5)) + expect(overlayWrapper.getBoundingClientRect().top).toBe( + clientTopForLine(component, 5) + ) // Can update overlay wrapper class - decoration.setProperties({type: 'overlay', item: overlayElement, class: 'b'}) + decoration.setProperties({ + type: 'overlay', + item: overlayElement, + class: 'b' + }) await component.getNextUpdatePromise() expect(overlayWrapper.classList.contains('a')).toBe(false) expect(overlayWrapper.classList.contains('b')).toBe(true) - decoration.setProperties({type: 'overlay', item: overlayElement}) + decoration.setProperties({ type: 'overlay', item: overlayElement }) await component.getNextUpdatePromise() expect(overlayWrapper.classList.contains('b')).toBe(false) }) it('does not attempt to avoid overflowing the window if `avoidOverflow` is false on the decoration', async () => { - const {component, element, editor} = buildComponent({width: 200, height: 100, attach: false}) + const { component, element, editor } = buildComponent({ + width: 200, + height: 100, + attach: false + }) const fakeWindow = attachFakeWindow(component) const overlayElement = document.createElement('div') overlayElement.style.width = '50px' @@ -1889,46 +2646,58 @@ describe('TextEditorComponent', () => { overlayElement.style.margin = '3px' overlayElement.style.backgroundColor = 'red' const marker = editor.markScreenPosition([4, 25]) - const decoration = editor.decorateMarker(marker, {type: 'overlay', item: overlayElement, avoidOverflow: false}) + const decoration = editor.decorateMarker(marker, { + type: 'overlay', + item: overlayElement, + avoidOverflow: false + }) await component.getNextUpdatePromise() await setScrollLeft(component, 30) - expect(overlayElement.getBoundingClientRect().right).toBeGreaterThan(fakeWindow.getBoundingClientRect().right) + expect(overlayElement.getBoundingClientRect().right).toBeGreaterThan( + fakeWindow.getBoundingClientRect().right + ) await setScrollLeft(component, 280) - expect(overlayElement.getBoundingClientRect().left).toBeLessThan(fakeWindow.getBoundingClientRect().left) + expect(overlayElement.getBoundingClientRect().left).toBeLessThan( + fakeWindow.getBoundingClientRect().left + ) }) }) describe('custom gutter decorations', () => { it('arranges custom gutters based on their priority', async () => { - const {component, element, editor} = buildComponent() - editor.addGutter({name: 'e', priority: 2}) - editor.addGutter({name: 'a', priority: -2}) - editor.addGutter({name: 'd', priority: 1}) - editor.addGutter({name: 'b', priority: -1}) - editor.addGutter({name: 'c', priority: 0}) + const { component, element, editor } = buildComponent() + editor.addGutter({ name: 'e', priority: 2 }) + editor.addGutter({ name: 'a', priority: -2 }) + editor.addGutter({ name: 'd', priority: 1 }) + editor.addGutter({ name: 'b', priority: -1 }) + editor.addGutter({ name: 'c', priority: 0 }) await component.getNextUpdatePromise() - const gutters = component.refs.gutterContainer.element.querySelectorAll('.gutter') - expect(Array.from(gutters).map((g) => g.getAttribute('gutter-name'))).toEqual([ - 'a', 'b', 'c', 'line-number', 'd', 'e' - ]) + const gutters = component.refs.gutterContainer.element.querySelectorAll( + '.gutter' + ) + expect( + Array.from(gutters).map(g => g.getAttribute('gutter-name')) + ).toEqual(['a', 'b', 'c', 'line-number', 'd', 'e']) }) it('adjusts the left edge of the scroll container based on changes to the gutter container width', async () => { - const {component, element, editor} = buildComponent() - const {scrollContainer, gutterContainer} = component.refs + const { component, element, editor } = buildComponent() + const { scrollContainer, gutterContainer } = component.refs function checkScrollContainerLeft () { - expect(scrollContainer.getBoundingClientRect().left).toBe(Math.round(gutterContainer.element.getBoundingClientRect().right)) + expect(scrollContainer.getBoundingClientRect().left).toBe( + Math.round(gutterContainer.element.getBoundingClientRect().right) + ) } checkScrollContainerLeft() - const gutterA = editor.addGutter({name: 'a'}) + const gutterA = editor.addGutter({ name: 'a' }) await component.getNextUpdatePromise() checkScrollContainerLeft() - const gutterB = editor.addGutter({name: 'b'}) + const gutterB = editor.addGutter({ name: 'b' }) await component.getNextUpdatePromise() checkScrollContainerLeft() @@ -1954,10 +2723,10 @@ describe('TextEditorComponent', () => { }) it('allows the element of custom gutters to be retrieved before being rendered in the editor component', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const [lineNumberGutter] = editor.getGutters() - const gutterA = editor.addGutter({name: 'a', priority: -1}) - const gutterB = editor.addGutter({name: 'b', priority: 1}) + const gutterA = editor.addGutter({ name: 'a', priority: -1 }) + const gutterB = editor.addGutter({ name: 'b', priority: 1 }) const lineNumberGutterElement = lineNumberGutter.getElement() const gutterAElement = gutterA.getElement() @@ -1971,9 +2740,9 @@ describe('TextEditorComponent', () => { }) it('can show and hide custom gutters', async () => { - const {component, element, editor} = buildComponent() - const gutterA = editor.addGutter({name: 'a', priority: -1}) - const gutterB = editor.addGutter({name: 'b', priority: 1}) + const { component, element, editor } = buildComponent() + const gutterA = editor.addGutter({ name: 'a', priority: -1 }) + const gutterB = editor.addGutter({ name: 'b', priority: 1 }) const gutterAElement = gutterA.getElement() const gutterBElement = gutterB.getElement() @@ -1998,9 +2767,9 @@ describe('TextEditorComponent', () => { }) it('renders decorations in custom gutters', async () => { - const {component, element, editor} = buildComponent() - const gutterA = editor.addGutter({name: 'a', priority: -1}) - const gutterB = editor.addGutter({name: 'b', priority: 1}) + const { component, element, editor } = buildComponent() + const gutterA = editor.addGutter({ name: 'a', priority: -1 }) + const gutterB = editor.addGutter({ name: 'b', priority: 1 }) const marker1 = editor.markScreenRange([[2, 0], [4, 0]]) const marker2 = editor.markScreenRange([[6, 0], [7, 0]]) const marker3 = editor.markScreenRange([[9, 0], [12, 0]]) @@ -2009,42 +2778,68 @@ describe('TextEditorComponent', () => { // Packages may adopt this class name for decorations to be styled the same as line numbers decorationElement2.className = 'line-number' - const decoration1 = gutterA.decorateMarker(marker1, {class: 'a'}) - const decoration2 = gutterA.decorateMarker(marker2, {class: 'b', item: decorationElement1}) - const decoration3 = gutterB.decorateMarker(marker3, {item: decorationElement2}) + const decoration1 = gutterA.decorateMarker(marker1, { class: 'a' }) + const decoration2 = gutterA.decorateMarker(marker2, { + class: 'b', + item: decorationElement1 + }) + const decoration3 = gutterB.decorateMarker(marker3, { + item: decorationElement2 + }) await component.getNextUpdatePromise() - let [decorationNode1, decorationNode2] = gutterA.getElement().firstChild.children + let [ + decorationNode1, + decorationNode2 + ] = gutterA.getElement().firstChild.children const [decorationNode3] = gutterB.getElement().firstChild.children expect(decorationNode1.className).toBe('decoration a') - expect(decorationNode1.getBoundingClientRect().top).toBe(clientTopForLine(component, 2)) - expect(decorationNode1.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 5)) + expect(decorationNode1.getBoundingClientRect().top).toBe( + clientTopForLine(component, 2) + ) + expect(decorationNode1.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 5) + ) expect(decorationNode1.firstChild).toBeNull() expect(decorationNode2.className).toBe('decoration b') - expect(decorationNode2.getBoundingClientRect().top).toBe(clientTopForLine(component, 6)) - expect(decorationNode2.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 8)) + expect(decorationNode2.getBoundingClientRect().top).toBe( + clientTopForLine(component, 6) + ) + expect(decorationNode2.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 8) + ) expect(decorationNode2.firstChild).toBe(decorationElement1) expect(decorationElement1.offsetHeight).toBe(decorationNode2.offsetHeight) expect(decorationElement1.offsetWidth).toBe(decorationNode2.offsetWidth) expect(decorationNode3.className).toBe('decoration') - expect(decorationNode3.getBoundingClientRect().top).toBe(clientTopForLine(component, 9)) - expect(decorationNode3.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 12) + component.getLineHeight()) + expect(decorationNode3.getBoundingClientRect().top).toBe( + clientTopForLine(component, 9) + ) + expect(decorationNode3.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 12) + component.getLineHeight() + ) expect(decorationNode3.firstChild).toBe(decorationElement2) expect(decorationElement2.offsetHeight).toBe(decorationNode3.offsetHeight) expect(decorationElement2.offsetWidth).toBe(decorationNode3.offsetWidth) // Inline styled height is updated when line height changes - element.style.fontSize = parseInt(getComputedStyle(element).fontSize) + 10 + 'px' + element.style.fontSize = + parseInt(getComputedStyle(element).fontSize) + 10 + 'px' TextEditor.didUpdateStyles() await component.getNextUpdatePromise() expect(decorationElement1.offsetHeight).toBe(decorationNode2.offsetHeight) expect(decorationElement2.offsetHeight).toBe(decorationNode3.offsetHeight) - decoration1.setProperties({type: 'gutter', gutterName: 'a', class: 'c', item: decorationElement1}) - decoration2.setProperties({type: 'gutter', gutterName: 'a'}) + decoration1.setProperties({ + type: 'gutter', + gutterName: 'a', + class: 'c', + item: decorationElement1 + }) + decoration2.setProperties({ type: 'gutter', gutterName: 'a' }) decoration3.destroy() await component.getNextUpdatePromise() expect(decorationNode1.className).toBe('decoration c') @@ -2056,44 +2851,62 @@ describe('TextEditorComponent', () => { }) it('renders custom line number gutters', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() const gutterA = editor.addGutter({ name: 'a', priority: 1, type: 'line-number', class: 'a-number', - labelFn: ({bufferRow}) => `a - ${bufferRow}` + labelFn: ({ bufferRow }) => `a - ${bufferRow}` }) const gutterB = editor.addGutter({ name: 'b', priority: 1, type: 'line-number', class: 'b-number', - labelFn: ({bufferRow}) => `b - ${bufferRow}` + labelFn: ({ bufferRow }) => `b - ${bufferRow}` }) editor.setText('0000\n0001\n0002\n0003\n0004\n') await component.getNextUpdatePromise() const gutterAElement = gutterA.getElement() - const aNumbers = gutterAElement.querySelectorAll('div.line-number[data-buffer-row]') + const aNumbers = gutterAElement.querySelectorAll( + 'div.line-number[data-buffer-row]' + ) const aLabels = Array.from(aNumbers, e => e.textContent) - expect(aLabels).toEqual(['a - 0', 'a - 1', 'a - 2', 'a - 3', 'a - 4', 'a - 5']) + expect(aLabels).toEqual([ + 'a - 0', + 'a - 1', + 'a - 2', + 'a - 3', + 'a - 4', + 'a - 5' + ]) const gutterBElement = gutterB.getElement() - const bNumbers = gutterBElement.querySelectorAll('div.line-number[data-buffer-row]') + const bNumbers = gutterBElement.querySelectorAll( + 'div.line-number[data-buffer-row]' + ) const bLabels = Array.from(bNumbers, e => e.textContent) - expect(bLabels).toEqual(['b - 0', 'b - 1', 'b - 2', 'b - 3', 'b - 4', 'b - 5']) + expect(bLabels).toEqual([ + 'b - 0', + 'b - 1', + 'b - 2', + 'b - 3', + 'b - 4', + 'b - 5' + ]) }) it("updates the editor's soft wrap width when a custom gutter's measurement is available", () => { - const {component, element, editor} = buildComponent({ + const { component, element, editor } = buildComponent({ lineNumberGutterVisible: false, width: 400, softWrapped: true, - attach: false, + attach: false }) - const gutter = editor.addGutter({name: 'a', priority: 10}) + const gutter = editor.addGutter({ name: 'a', priority: 10 }) gutter.getElement().style.width = '100px' jasmine.attachToDOM(element) @@ -2102,30 +2915,53 @@ describe('TextEditorComponent', () => { // Component client width - gutter container width - vertical scrollbar width const softWrapColumn = Math.floor( - (400 - 100 - component.getVerticalScrollbarWidth()) / component.getBaseCharacterWidth()) + (400 - 100 - component.getVerticalScrollbarWidth()) / + component.getBaseCharacterWidth() + ) expect(editor.getSoftWrapColumn()).toBe(softWrapColumn) }) }) describe('block decorations', () => { it('renders visible block decorations between the appropriate lines, refreshing and measuring them as needed', async () => { - const editor = buildEditor({autoHeight: false}) - const {item: item1, decoration: decoration1} = createBlockDecorationAtScreenRow(editor, 0, {height: 11, position: 'before'}) - const {item: item2, decoration: decoration2} = createBlockDecorationAtScreenRow(editor, 2, {height: 22, margin: 10, position: 'before'}) + const editor = buildEditor({ autoHeight: false }) + const { + item: item1, + decoration: decoration1 + } = createBlockDecorationAtScreenRow(editor, 0, { + height: 11, + position: 'before' + }) + const { + item: item2, + decoration: decoration2 + } = createBlockDecorationAtScreenRow(editor, 2, { + height: 22, + margin: 10, + position: 'before' + }) // render an editor that already contains some block decorations - const {component, element} = buildComponent({editor, rowsPerTile: 3}) - element.style.height = 4 * component.getLineHeight() + horizontalScrollbarHeight + 'px' + const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) + element.style.height = + 4 * component.getLineHeight() + horizontalScrollbarHeight + 'px' await component.getNextUpdatePromise() expect(component.getRenderedStartRow()).toBe(0) expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item1) + getElementHeight(item2) + getElementHeight(item1) + + getElementHeight(item2) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item1) + getElementHeight(item2)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item1) + + getElementHeight(item2) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2135,21 +2971,60 @@ describe('TextEditorComponent', () => { expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 2)) // add block decorations - const {item: item3, decoration: decoration3} = createBlockDecorationAtScreenRow(editor, 4, {height: 33, position: 'before'}) - const {item: item4, decoration: decoration4} = createBlockDecorationAtScreenRow(editor, 7, {height: 44, position: 'before'}) - const {item: item5, decoration: decoration5} = createBlockDecorationAtScreenRow(editor, 7, {height: 50, marginBottom: 5, position: 'after'}) - const {item: item6, decoration: decoration6} = createBlockDecorationAtScreenRow(editor, 12, {height: 60, marginTop: 6, position: 'after'}) + const { + item: item3, + decoration: decoration3 + } = createBlockDecorationAtScreenRow(editor, 4, { + height: 33, + position: 'before' + }) + const { + item: item4, + decoration: decoration4 + } = createBlockDecorationAtScreenRow(editor, 7, { + height: 44, + position: 'before' + }) + const { + item: item5, + decoration: decoration5 + } = createBlockDecorationAtScreenRow(editor, 7, { + height: 50, + marginBottom: 5, + position: 'after' + }) + const { + item: item6, + decoration: decoration6 + } = createBlockDecorationAtScreenRow(editor, 12, { + height: 60, + marginTop: 6, + position: 'after' + }) await component.getNextUpdatePromise() expect(component.getRenderedStartRow()).toBe(0) expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item1) + getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item1) + + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item1) + getElementHeight(item2)}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item3)} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item1) + + getElementHeight(item2) + }, + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + getElementHeight(item3) + } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2170,12 +3045,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2)}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item3)} + { + tileStartRow: 0, + height: 3 * component.getLineHeight() + getElementHeight(item2) + }, + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + getElementHeight(item3) + } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2196,12 +3080,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2221,12 +3114,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item2)} + { + tileStartRow: 0, + height: 3 * component.getLineHeight() + getElementHeight(item3) + }, + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + getElementHeight(item2) + } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2240,17 +3142,26 @@ describe('TextEditorComponent', () => { expect(element.contains(item6)).toBe(false) // scroll past the first tile - await setScrollTop(component, 3 * component.getLineHeight() + getElementHeight(item3)) + await setScrollTop( + component, + 3 * component.getLineHeight() + getElementHeight(item3) + ) expect(component.getRenderedStartRow()).toBe(3) expect(component.getRenderedEndRow()).toBe(12) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item2)}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + getElementHeight(item2) + }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2270,12 +3181,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2300,12 +3220,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2323,27 +3252,39 @@ describe('TextEditorComponent', () => { item3.style.margin = '' item3.style.width = '' item3.style.wordWrap = 'break-word' - const contentWidthInCharacters = Math.floor(component.getScrollContainerClientWidth() / component.getBaseCharacterWidth()) + const contentWidthInCharacters = Math.floor( + component.getScrollContainerClientWidth() / + component.getBaseCharacterWidth() + ) item3.textContent = 'x'.repeat(contentWidthInCharacters * 2) await component.getNextUpdatePromise() // make the editor wider, so that the decoration doesn't wrap anymore. - component.element.style.width = ( + component.element.style.width = component.getGutterContainerWidth() + component.getScrollContainerClientWidth() * 2 + - verticalScrollbarWidth - ) + 'px' + verticalScrollbarWidth + + 'px' await component.getNextUpdatePromise() expect(component.getRenderedStartRow()).toBe(0) expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2364,13 +3305,28 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(13) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight() + getElementHeight(item4) + getElementHeight(item5)}, + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { + tileStartRow: 6, + height: + 3 * component.getLineHeight() + + getElementHeight(item4) + + getElementHeight(item5) + } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(13) @@ -2387,47 +3343,72 @@ describe('TextEditorComponent', () => { }) it('correctly positions line numbers when block decorations are located at tile boundaries', async () => { - const {editor, component, element} = buildComponent({rowsPerTile: 3}) - createBlockDecorationAtScreenRow(editor, 0, {height: 5, position: 'before'}) - createBlockDecorationAtScreenRow(editor, 2, {height: 7, position: 'after'}) - createBlockDecorationAtScreenRow(editor, 3, {height: 9, position: 'before'}) - createBlockDecorationAtScreenRow(editor, 3, {height: 11, position: 'after'}) - createBlockDecorationAtScreenRow(editor, 5, {height: 13, position: 'after'}) + const { editor, component, element } = buildComponent({ rowsPerTile: 3 }) + createBlockDecorationAtScreenRow(editor, 0, { + height: 5, + position: 'before' + }) + createBlockDecorationAtScreenRow(editor, 2, { + height: 7, + position: 'after' + }) + createBlockDecorationAtScreenRow(editor, 3, { + height: 9, + position: 'before' + }) + createBlockDecorationAtScreenRow(editor, 3, { + height: 11, + position: 'after' + }) + createBlockDecorationAtScreenRow(editor, 5, { + height: 13, + position: 'after' + }) await component.getNextUpdatePromise() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + 5 + 7}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + 9 + 11 + 13}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() + 5 + 7 }, + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + 9 + 11 + 13 + }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('removes block decorations whose markers have been destroyed', async () => { - const {editor, component, element} = buildComponent({rowsPerTile: 3}) - const {marker} = createBlockDecorationAtScreenRow(editor, 2, {height: 5, position: 'before'}) + const { editor, component, element } = buildComponent({ rowsPerTile: 3 }) + const { marker } = createBlockDecorationAtScreenRow(editor, 2, { + height: 5, + position: 'before' + }) await component.getNextUpdatePromise() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + 5}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() + 5 }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) marker.destroy() await component.getNextUpdatePromise() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('removes block decorations whose markers are invalidated, and adds them back when they become valid again', async () => { - const editor = buildEditor({rowsPerTile: 3, autoHeight: false}) - const {item, decoration, marker} = createBlockDecorationAtScreenRow(editor, 3, {height: 44, position: 'before', invalidate: 'touch'}) - const {component, element} = buildComponent({editor, rowsPerTile: 3}) + const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) + const { item, decoration, marker } = createBlockDecorationAtScreenRow( + editor, + 3, + { height: 44, position: 'before', invalidate: 'touch' } + ) + const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) // Invalidating the marker removes the block decoration. editor.getBuffer().deleteRows(2, 3) @@ -2435,9 +3416,9 @@ describe('TextEditorComponent', () => { expect(item.parentElement).toBeNull() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) // Moving invalid markers is ignored. @@ -2446,9 +3427,9 @@ describe('TextEditorComponent', () => { expect(item.parentElement).toBeNull() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) // Making the marker valid again adds back the block decoration. @@ -2458,9 +3439,9 @@ describe('TextEditorComponent', () => { expect(item.nextSibling).toBe(lineNodeForScreenRow(component, 3)) assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + 44}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() + 44 }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) // Destroying the decoration and invalidating the marker at the same time @@ -2471,30 +3452,34 @@ describe('TextEditorComponent', () => { expect(item.parentElement).toBeNull() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('does not render block decorations when decorating invalid markers', async () => { - const editor = buildEditor({rowsPerTile: 3, autoHeight: false}) - const {component, element} = buildComponent({editor, rowsPerTile: 3}) + const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) + const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) - const marker = editor.markScreenPosition([3, 0], {invalidate: 'touch'}) + const marker = editor.markScreenPosition([3, 0], { invalidate: 'touch' }) const item = document.createElement('div') item.style.height = 30 + 'px' item.style.width = 30 + 'px' editor.getBuffer().deleteRows(1, 4) - const decoration = editor.decorateMarker(marker, {type: 'block', item, position: 'before'}) + const decoration = editor.decorateMarker(marker, { + type: 'block', + item, + position: 'before' + }) await component.getNextUpdatePromise() expect(item.parentElement).toBeNull() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) // Making the marker valid again causes the corresponding block decoration @@ -2505,16 +3490,20 @@ describe('TextEditorComponent', () => { expect(item.nextSibling).toBe(lineNodeForScreenRow(component, 2)) assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + 30}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() + 30 }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('does not try to remeasure block decorations whose markers are invalid (regression)', async () => { - const editor = buildEditor({rowsPerTile: 3, autoHeight: false}) - const {component, element} = buildComponent({editor, rowsPerTile: 3}) - const {decoration, marker} = createBlockDecorationAtScreenRow(editor, 2, {height: '12px', invalidate: 'touch'}) + const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) + const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) + const { decoration, marker } = createBlockDecorationAtScreenRow( + editor, + 2, + { height: '12px', invalidate: 'touch' } + ) editor.getBuffer().deleteRows(0, 3) await component.getNextUpdatePromise() @@ -2522,19 +3511,21 @@ describe('TextEditorComponent', () => { await setEditorWidthInCharacters(component, 20) assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('does not throw exceptions when destroying a block decoration inside a marker change event (regression)', async () => { - const {editor, component} = buildComponent({rowsPerTile: 3}) + const { editor, component } = buildComponent({ rowsPerTile: 3 }) const marker = editor.markScreenPosition([2, 0]) - marker.onDidChange(() => { marker.destroy() }) + marker.onDidChange(() => { + marker.destroy() + }) const item = document.createElement('div') - editor.decorateMarker(marker, {type: 'block', item}) + editor.decorateMarker(marker, { type: 'block', item }) await component.getNextUpdatePromise() expect(item.nextSibling).toBe(lineNodeForScreenRow(component, 2)) @@ -2547,18 +3538,25 @@ describe('TextEditorComponent', () => { }) it('does not attempt to render block decorations located outside the visible range', async () => { - const {editor, component} = buildComponent({autoHeight: false, rowsPerTile: 2}) + const { editor, component } = buildComponent({ + autoHeight: false, + rowsPerTile: 2 + }) await setEditorHeightInLines(component, 2) expect(component.getRenderedStartRow()).toBe(0) expect(component.getRenderedEndRow()).toBe(4) - const marker1 = editor.markScreenRange([[3, 0], [5, 0]], {reversed: false}) + const marker1 = editor.markScreenRange([[3, 0], [5, 0]], { + reversed: false + }) const item1 = document.createElement('div') - editor.decorateMarker(marker1, {type: 'block', item: item1}) + editor.decorateMarker(marker1, { type: 'block', item: item1 }) - const marker2 = editor.markScreenRange([[3, 0], [5, 0]], {reversed: true}) + const marker2 = editor.markScreenRange([[3, 0], [5, 0]], { + reversed: true + }) const item2 = document.createElement('div') - editor.decorateMarker(marker2, {type: 'block', item: item2}) + editor.decorateMarker(marker2, { type: 'block', item: item2 }) await component.getNextUpdatePromise() expect(item1.parentElement).toBeNull() @@ -2573,22 +3571,35 @@ describe('TextEditorComponent', () => { it('measures block decorations correctly when they are added before the component width has been updated', async () => { { - const {editor, component, element} = buildComponent({autoHeight: false, width: 500, attach: false}) + const { editor, component, element } = buildComponent({ + autoHeight: false, + width: 500, + attach: false + }) const marker = editor.markScreenPosition([0, 0]) const item = document.createElement('div') item.textContent = 'block decoration' - const decoration = editor.decorateMarker(marker, {type: 'block', item}) + const decoration = editor.decorateMarker(marker, { + type: 'block', + item + }) jasmine.attachToDOM(element) assertLinesAreAlignedWithLineNumbers(component) } { - const {editor, component, element} = buildComponent({autoHeight: false, width: 800}) + const { editor, component, element } = buildComponent({ + autoHeight: false, + width: 800 + }) const marker = editor.markScreenPosition([0, 0]) const item = document.createElement('div') item.textContent = 'block decoration that could wrap many times' - const decoration = editor.decorateMarker(marker, {type: 'block', item}) + const decoration = editor.decorateMarker(marker, { + type: 'block', + item + }) element.style.width = '50px' await component.getNextUpdatePromise() @@ -2597,16 +3608,23 @@ describe('TextEditorComponent', () => { }) it('bases the width of the block decoration measurement area on the editor scroll width', async () => { - const {component, element} = buildComponent({autoHeight: false, width: 150}) - expect(component.refs.blockDecorationMeasurementArea.offsetWidth).toBe(component.getScrollWidth()) + const { component, element } = buildComponent({ + autoHeight: false, + width: 150 + }) + expect(component.refs.blockDecorationMeasurementArea.offsetWidth).toBe( + component.getScrollWidth() + ) element.style.width = '800px' await component.getNextUpdatePromise() - expect(component.refs.blockDecorationMeasurementArea.offsetWidth).toBe(component.getScrollWidth()) + expect(component.refs.blockDecorationMeasurementArea.offsetWidth).toBe( + component.getScrollWidth() + ) }) it('does not change the cursor position when clicking on a block decoration', async () => { - const {editor, component} = buildComponent() + const { editor, component } = buildComponent() const decorationElement = document.createElement('div') decorationElement.textContent = 'Parent' @@ -2614,7 +3632,7 @@ describe('TextEditorComponent', () => { childElement.textContent = 'Child' decorationElement.appendChild(childElement) const marker = editor.markScreenPosition([4, 0]) - editor.decorateMarker(marker, {type: 'block', item: decorationElement}) + editor.decorateMarker(marker, { type: 'block', item: decorationElement }) await component.getNextUpdatePromise() const decorationElementClientRect = decorationElement.getBoundingClientRect() @@ -2639,38 +3657,64 @@ describe('TextEditorComponent', () => { }) it('uses the order property to control the order of block decorations at the same screen row', async () => { - const editor = buildEditor({autoHeight: false}) - const {component, element} = buildComponent({editor}) - element.style.height = 10 * component.getLineHeight() + horizontalScrollbarHeight + 'px' + const editor = buildEditor({ autoHeight: false }) + const { component, element } = buildComponent({ editor }) + element.style.height = + 10 * component.getLineHeight() + horizontalScrollbarHeight + 'px' await component.getNextUpdatePromise() // Order parameters that differ from creation order; that collide; and that are not provided. - const [beforeItems, beforeDecorations] = [30, 20, undefined, 20, 10, undefined].map(order => { - return createBlockDecorationAtScreenRow(editor, 2, {height: 10, position: 'before', order}) - }).reduce((lists, result) => { - lists[0].push(result.item) - lists[1].push(result.decoration) - return lists - }, [[], []]) + const [beforeItems, beforeDecorations] = [ + 30, + 20, + undefined, + 20, + 10, + undefined + ] + .map(order => { + return createBlockDecorationAtScreenRow(editor, 2, { + height: 10, + position: 'before', + order + }) + }) + .reduce((lists, result) => { + lists[0].push(result.item) + lists[1].push(result.decoration) + return lists + }, [[], []]) - const [afterItems, afterDecorations] = [undefined, 1, 6, undefined, 6, 2].map(order => { - return createBlockDecorationAtScreenRow(editor, 2, {height: 10, position: 'after', order}) - }).reduce((lists, result) => { - lists[0].push(result.item) - lists[1].push(result.decoration) - return lists - }, [[], []]) + const [afterItems, afterDecorations] = [undefined, 1, 6, undefined, 6, 2] + .map(order => { + return createBlockDecorationAtScreenRow(editor, 2, { + height: 10, + position: 'after', + order + }) + }) + .reduce((lists, result) => { + lists[0].push(result.item) + lists[1].push(result.decoration) + return lists + }, [[], []]) await component.getNextUpdatePromise() - expect(beforeItems[4].previousSibling).toBe(lineNodeForScreenRow(component, 1)) + expect(beforeItems[4].previousSibling).toBe( + lineNodeForScreenRow(component, 1) + ) expect(beforeItems[4].nextSibling).toBe(beforeItems[1]) expect(beforeItems[1].nextSibling).toBe(beforeItems[3]) expect(beforeItems[3].nextSibling).toBe(beforeItems[0]) expect(beforeItems[0].nextSibling).toBe(beforeItems[2]) expect(beforeItems[2].nextSibling).toBe(beforeItems[5]) - expect(beforeItems[5].nextSibling).toBe(lineNodeForScreenRow(component, 2)) - expect(afterItems[1].previousSibling).toBe(lineNodeForScreenRow(component, 2)) + expect(beforeItems[5].nextSibling).toBe( + lineNodeForScreenRow(component, 2) + ) + expect(afterItems[1].previousSibling).toBe( + lineNodeForScreenRow(component, 2) + ) expect(afterItems[1].nextSibling).toBe(afterItems[5]) expect(afterItems[5].nextSibling).toBe(afterItems[2]) expect(afterItems[2].nextSibling).toBe(afterItems[4]) @@ -2678,7 +3722,11 @@ describe('TextEditorComponent', () => { expect(afterItems[0].nextSibling).toBe(afterItems[3]) // Create a decoration somewhere else and move it to the same screen row as the existing decorations - const {item: later, decoration} = createBlockDecorationAtScreenRow(editor, 4, {height: 20, position: 'after', order: 3}) + const { item: later, decoration } = createBlockDecorationAtScreenRow( + editor, + 4, + { height: 20, position: 'after', order: 3 } + ) await component.getNextUpdatePromise() expect(later.previousSibling).toBe(lineNodeForScreenRow(component, 4)) expect(later.nextSibling).toBe(lineNodeForScreenRow(component, 5)) @@ -2691,38 +3739,63 @@ describe('TextEditorComponent', () => { // Move a decoration away from its screen row and ensure the rest maintain their order beforeDecorations[3].getMarker().setHeadScreenPosition([5, 0]) await component.getNextUpdatePromise() - expect(beforeItems[3].previousSibling).toBe(lineNodeForScreenRow(component, 4)) - expect(beforeItems[3].nextSibling).toBe(lineNodeForScreenRow(component, 5)) + expect(beforeItems[3].previousSibling).toBe( + lineNodeForScreenRow(component, 4) + ) + expect(beforeItems[3].nextSibling).toBe( + lineNodeForScreenRow(component, 5) + ) - expect(beforeItems[4].previousSibling).toBe(lineNodeForScreenRow(component, 1)) + expect(beforeItems[4].previousSibling).toBe( + lineNodeForScreenRow(component, 1) + ) expect(beforeItems[4].nextSibling).toBe(beforeItems[1]) expect(beforeItems[1].nextSibling).toBe(beforeItems[0]) expect(beforeItems[0].nextSibling).toBe(beforeItems[2]) expect(beforeItems[2].nextSibling).toBe(beforeItems[5]) - expect(beforeItems[5].nextSibling).toBe(lineNodeForScreenRow(component, 2)) - }); + expect(beforeItems[5].nextSibling).toBe( + lineNodeForScreenRow(component, 2) + ) + }) - function createBlockDecorationAtScreenRow(editor, screenRow, {height, margin, marginTop, marginBottom, position, order, invalidate}) { - const marker = editor.markScreenPosition([screenRow, 0], {invalidate: invalidate || 'never'}) + function createBlockDecorationAtScreenRow ( + editor, + screenRow, + { height, margin, marginTop, marginBottom, position, order, invalidate } + ) { + const marker = editor.markScreenPosition([screenRow, 0], { + invalidate: invalidate || 'never' + }) const item = document.createElement('div') item.style.height = height + 'px' if (margin != null) item.style.margin = margin + 'px' if (marginTop != null) item.style.marginTop = marginTop + 'px' if (marginBottom != null) item.style.marginBottom = marginBottom + 'px' item.style.width = 30 + 'px' - const decoration = editor.decorateMarker(marker, {type: 'block', item, position, order}) - return {item, decoration, marker} + const decoration = editor.decorateMarker(marker, { + type: 'block', + item, + position, + order + }) + return { item, decoration, marker } } function assertTilesAreSizedAndPositionedCorrectly (component, tiles) { let top = 0 for (let tile of tiles) { - const linesTileElement = lineNodeForScreenRow(component, tile.tileStartRow).parentElement + const linesTileElement = lineNodeForScreenRow( + component, + tile.tileStartRow + ).parentElement const linesTileBoundingRect = linesTileElement.getBoundingClientRect() expect(linesTileBoundingRect.height).toBe(tile.height) expect(linesTileBoundingRect.top).toBe(top) - const lineNumbersTileElement = lineNumberNodeForScreenRow(component, tile.tileStartRow).parentElement + const lineNumbersTileElement = lineNumberNodeForScreenRow( + component, + tile.tileStartRow + ).parentElement const lineNumbersTileBoundingRect = lineNumbersTileElement.getBoundingClientRect() expect(lineNumbersTileBoundingRect.height).toBe(tile.height) expect(lineNumbersTileBoundingRect.top).toBe(top) @@ -2737,27 +3810,37 @@ describe('TextEditorComponent', () => { for (let row = startRow; row < endRow; row++) { const lineNode = lineNodeForScreenRow(component, row) const lineNumberNode = lineNumberNodeForScreenRow(component, row) - expect(lineNumberNode.getBoundingClientRect().top).toBe(lineNode.getBoundingClientRect().top) + expect(lineNumberNode.getBoundingClientRect().top).toBe( + lineNode.getBoundingClientRect().top + ) } } }) describe('cursor decorations', () => { it('allows default cursors to be customized', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.addCursorAtScreenPosition([1, 0]) - const [cursorMarker1, cursorMarker2] = editor.getCursors().map(c => c.getMarker()) + const [cursorMarker1, cursorMarker2] = editor + .getCursors() + .map(c => c.getMarker()) - editor.decorateMarker(cursorMarker1, {type: 'cursor', class: 'a'}) - editor.decorateMarker(cursorMarker2, {type: 'cursor', class: 'b', style: {visibility: 'hidden'}}) - editor.decorateMarker(cursorMarker2, {type: 'cursor', style: {backgroundColor: 'red'}}) + editor.decorateMarker(cursorMarker1, { type: 'cursor', class: 'a' }) + editor.decorateMarker(cursorMarker2, { + type: 'cursor', + class: 'b', + style: { visibility: 'hidden' } + }) + editor.decorateMarker(cursorMarker2, { + type: 'cursor', + style: { backgroundColor: 'red' } + }) await component.getNextUpdatePromise() const cursorNodes = element.querySelectorAll('.cursor') expect(cursorNodes.length).toBe(2) - expect(cursorNodes[0].className).toBe('cursor a') expect(cursorNodes[1].className).toBe('cursor b') expect(cursorNodes[1].style.visibility).toBe('hidden') @@ -2765,9 +3848,9 @@ describe('TextEditorComponent', () => { }) it('allows markers that are not actually associated with cursors to be decorated as if they were cursors', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenPosition([1, 0]) - editor.decorateMarker(marker, {type: 'cursor', class: 'a'}) + editor.decorateMarker(marker, { type: 'cursor', class: 'a' }) await component.getNextUpdatePromise() const cursorNodes = element.querySelectorAll('.cursor') @@ -2779,30 +3862,60 @@ describe('TextEditorComponent', () => { describe('text decorations', () => { it('injects spans with custom class names and inline styles based on text decorations', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2}) + const { component, element, editor } = buildComponent({ rowsPerTile: 2 }) const markerLayer = editor.addMarkerLayer() const marker1 = markerLayer.markBufferRange([[0, 2], [2, 7]]) const marker2 = markerLayer.markBufferRange([[0, 2], [3, 8]]) const marker3 = markerLayer.markBufferRange([[1, 13], [2, 7]]) - editor.decorateMarker(marker1, {type: 'text', class: 'a', style: {color: 'red'}}) - editor.decorateMarker(marker2, {type: 'text', class: 'b', style: {color: 'blue'}}) - editor.decorateMarker(marker3, {type: 'text', class: 'c', style: {color: 'green'}}) + editor.decorateMarker(marker1, { + type: 'text', + class: 'a', + style: { color: 'red' } + }) + editor.decorateMarker(marker2, { + type: 'text', + class: 'b', + style: { color: 'blue' } + }) + editor.decorateMarker(marker3, { + type: 'text', + class: 'c', + style: { color: 'green' } + }) await component.getNextUpdatePromise() - expect(textContentOnRowMatchingSelector(component, 0, '.a')).toBe(editor.lineTextForScreenRow(0).slice(2)) - expect(textContentOnRowMatchingSelector(component, 1, '.a')).toBe(editor.lineTextForScreenRow(1)) - expect(textContentOnRowMatchingSelector(component, 2, '.a')).toBe(editor.lineTextForScreenRow(2).slice(0, 7)) + expect(textContentOnRowMatchingSelector(component, 0, '.a')).toBe( + editor.lineTextForScreenRow(0).slice(2) + ) + expect(textContentOnRowMatchingSelector(component, 1, '.a')).toBe( + editor.lineTextForScreenRow(1) + ) + expect(textContentOnRowMatchingSelector(component, 2, '.a')).toBe( + editor.lineTextForScreenRow(2).slice(0, 7) + ) expect(textContentOnRowMatchingSelector(component, 3, '.a')).toBe('') - expect(textContentOnRowMatchingSelector(component, 0, '.b')).toBe(editor.lineTextForScreenRow(0).slice(2)) - expect(textContentOnRowMatchingSelector(component, 1, '.b')).toBe(editor.lineTextForScreenRow(1)) - expect(textContentOnRowMatchingSelector(component, 2, '.b')).toBe(editor.lineTextForScreenRow(2)) - expect(textContentOnRowMatchingSelector(component, 3, '.b')).toBe(editor.lineTextForScreenRow(3).slice(0, 8)) + expect(textContentOnRowMatchingSelector(component, 0, '.b')).toBe( + editor.lineTextForScreenRow(0).slice(2) + ) + expect(textContentOnRowMatchingSelector(component, 1, '.b')).toBe( + editor.lineTextForScreenRow(1) + ) + expect(textContentOnRowMatchingSelector(component, 2, '.b')).toBe( + editor.lineTextForScreenRow(2) + ) + expect(textContentOnRowMatchingSelector(component, 3, '.b')).toBe( + editor.lineTextForScreenRow(3).slice(0, 8) + ) expect(textContentOnRowMatchingSelector(component, 0, '.c')).toBe('') - expect(textContentOnRowMatchingSelector(component, 1, '.c')).toBe(editor.lineTextForScreenRow(1).slice(13)) - expect(textContentOnRowMatchingSelector(component, 2, '.c')).toBe(editor.lineTextForScreenRow(2).slice(0, 7)) + expect(textContentOnRowMatchingSelector(component, 1, '.c')).toBe( + editor.lineTextForScreenRow(1).slice(13) + ) + expect(textContentOnRowMatchingSelector(component, 2, '.c')).toBe( + editor.lineTextForScreenRow(2).slice(0, 7) + ) expect(textContentOnRowMatchingSelector(component, 3, '.c')).toBe('') for (const span of element.querySelectorAll('.a:not(.c)')) { @@ -2817,11 +3930,16 @@ describe('TextEditorComponent', () => { marker2.setHeadScreenPosition([3, 10]) await component.getNextUpdatePromise() - expect(textContentOnRowMatchingSelector(component, 3, '.b')).toBe(editor.lineTextForScreenRow(3).slice(0, 10)) + expect(textContentOnRowMatchingSelector(component, 3, '.b')).toBe( + editor.lineTextForScreenRow(3).slice(0, 10) + ) }) it('correctly handles text decorations starting before the first rendered row and/or ending after the last rendered row', async () => { - const {component, element, editor} = buildComponent({autoHeight: false, rowsPerTile: 1}) + const { component, element, editor } = buildComponent({ + autoHeight: false, + rowsPerTile: 1 + }) element.style.height = 4 * component.getLineHeight() + 'px' await component.getNextUpdatePromise() await setScrollTop(component, 4 * component.getLineHeight()) @@ -2831,11 +3949,13 @@ describe('TextEditorComponent', () => { const markerLayer = editor.addMarkerLayer() const marker1 = markerLayer.markBufferRange([[0, 0], [4, 5]]) const marker2 = markerLayer.markBufferRange([[7, 2], [10, 8]]) - editor.decorateMarker(marker1, {type: 'text', class: 'a'}) - editor.decorateMarker(marker2, {type: 'text', class: 'b'}) + editor.decorateMarker(marker1, { type: 'text', class: 'a' }) + editor.decorateMarker(marker2, { type: 'text', class: 'b' }) await component.getNextUpdatePromise() - expect(textContentOnRowMatchingSelector(component, 4, '.a')).toBe(editor.lineTextForScreenRow(4).slice(0, 5)) + expect(textContentOnRowMatchingSelector(component, 4, '.a')).toBe( + editor.lineTextForScreenRow(4).slice(0, 5) + ) expect(textContentOnRowMatchingSelector(component, 5, '.a')).toBe('') expect(textContentOnRowMatchingSelector(component, 6, '.a')).toBe('') expect(textContentOnRowMatchingSelector(component, 7, '.a')).toBe('') @@ -2844,17 +3964,21 @@ describe('TextEditorComponent', () => { expect(textContentOnRowMatchingSelector(component, 4, '.b')).toBe('') expect(textContentOnRowMatchingSelector(component, 5, '.b')).toBe('') expect(textContentOnRowMatchingSelector(component, 6, '.b')).toBe('') - expect(textContentOnRowMatchingSelector(component, 7, '.b')).toBe(editor.lineTextForScreenRow(7).slice(2)) - expect(textContentOnRowMatchingSelector(component, 8, '.b')).toBe(editor.lineTextForScreenRow(8)) + expect(textContentOnRowMatchingSelector(component, 7, '.b')).toBe( + editor.lineTextForScreenRow(7).slice(2) + ) + expect(textContentOnRowMatchingSelector(component, 8, '.b')).toBe( + editor.lineTextForScreenRow(8) + ) }) it('does not create empty spans when a text decoration contains a row but another text decoration starts or ends at the beginning of it', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const markerLayer = editor.addMarkerLayer() const marker1 = markerLayer.markBufferRange([[0, 2], [4, 0]]) const marker2 = markerLayer.markBufferRange([[2, 0], [5, 8]]) - editor.decorateMarker(marker1, {type: 'text', class: 'a'}) - editor.decorateMarker(marker2, {type: 'text', class: 'b'}) + editor.decorateMarker(marker1, { type: 'text', class: 'a' }) + editor.decorateMarker(marker2, { type: 'text', class: 'b' }) await component.getNextUpdatePromise() for (const decorationSpan of element.querySelectorAll('.a, .b')) { expect(decorationSpan.textContent).not.toBe('') @@ -2862,9 +3986,9 @@ describe('TextEditorComponent', () => { }) it('does not create empty text nodes when a text decoration ends right after a text tag', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markBufferRange([[0, 8], [0, 29]]) - editor.decorateMarker(marker, {type: 'text', class: 'a'}) + editor.decorateMarker(marker, { type: 'text', class: 'a' }) await component.getNextUpdatePromise() for (const textNode of textNodesForScreenRow(component, 0)) { expect(textNode.textContent).not.toBe('') @@ -2872,8 +3996,10 @@ describe('TextEditorComponent', () => { }) function textContentOnRowMatchingSelector (component, row, selector) { - return Array.from(lineNodeForScreenRow(component, row).querySelectorAll(selector)) - .map((span) => span.textContent) + return Array.from( + lineNodeForScreenRow(component, row).querySelectorAll(selector) + ) + .map(span => span.textContent) .join('') } }) @@ -2883,10 +4009,12 @@ describe('TextEditorComponent', () => { describe('when there is only one cursor', () => { it('positions the cursor on single-click or when middle-clicking', async () => { for (const button of [0, 1]) { - const {component, element, editor} = buildComponent() - const {lineHeight} = component.measurements + const { component, element, editor } = buildComponent() + const { lineHeight } = component.measurements - editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false}) + editor.setCursorScreenPosition([Infinity, Infinity], { + autoscroll: false + }) component.didMouseDownOnContent({ detail: 1, button, @@ -2896,27 +4024,48 @@ describe('TextEditorComponent', () => { expect(editor.getCursorScreenPosition()).toEqual([0, 0]) const maxRow = editor.getLastScreenRow() - editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false}) + editor.setCursorScreenPosition([Infinity, Infinity], { + autoscroll: false + }) component.didMouseDownOnContent({ detail: 1, button, - clientX: clientLeftForCharacter(component, maxRow, editor.lineLengthForScreenRow(maxRow)) + 1, + clientX: + clientLeftForCharacter( + component, + maxRow, + editor.lineLengthForScreenRow(maxRow) + ) + 1, clientY: clientTopForLine(component, maxRow) + 1 }) - expect(editor.getCursorScreenPosition()).toEqual([maxRow, editor.lineLengthForScreenRow(maxRow)]) + expect(editor.getCursorScreenPosition()).toEqual([ + maxRow, + editor.lineLengthForScreenRow(maxRow) + ]) component.didMouseDownOnContent({ detail: 1, button, - clientX: clientLeftForCharacter(component, 0, editor.lineLengthForScreenRow(0)) + 1, + clientX: + clientLeftForCharacter( + component, + 0, + editor.lineLengthForScreenRow(0) + ) + 1, clientY: clientTopForLine(component, 0) + lineHeight / 2 }) - expect(editor.getCursorScreenPosition()).toEqual([0, editor.lineLengthForScreenRow(0)]) + expect(editor.getCursorScreenPosition()).toEqual([ + 0, + editor.lineLengthForScreenRow(0) + ]) component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 0) + clientLeftForCharacter(component, 3, 1)) / 2, + clientX: + (clientLeftForCharacter(component, 3, 0) + + clientLeftForCharacter(component, 3, 1)) / + 2, clientY: clientTopForLine(component, 1) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([1, 0]) @@ -2924,7 +4073,10 @@ describe('TextEditorComponent', () => { component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2, + clientX: + (clientLeftForCharacter(component, 3, 14) + + clientLeftForCharacter(component, 3, 15)) / + 2, clientY: clientTopForLine(component, 3) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([3, 14]) @@ -2932,7 +4084,11 @@ describe('TextEditorComponent', () => { component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2 + 1, + clientX: + (clientLeftForCharacter(component, 3, 14) + + clientLeftForCharacter(component, 3, 15)) / + 2 + + 1, clientY: clientTopForLine(component, 3) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([3, 15]) @@ -2943,7 +4099,10 @@ describe('TextEditorComponent', () => { component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2, + clientX: + (clientLeftForCharacter(component, 3, 14) + + clientLeftForCharacter(component, 3, 16)) / + 2, clientY: clientTopForLine(component, 3) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([3, 14]) @@ -2951,7 +4110,11 @@ describe('TextEditorComponent', () => { component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2 + 1, + clientX: + (clientLeftForCharacter(component, 3, 14) + + clientLeftForCharacter(component, 3, 16)) / + 2 + + 1, clientY: clientTopForLine(component, 3) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([3, 16]) @@ -2963,26 +4126,59 @@ describe('TextEditorComponent', () => { describe('when the input is for the primary mouse button', () => { it('selects words on double-click', () => { - const {component, editor} = buildComponent() - const {clientX, clientY} = clientPositionForCharacter(component, 1, 16) - component.didMouseDownOnContent({detail: 1, button: 0, clientX, clientY}) - component.didMouseDownOnContent({detail: 2, button: 0, clientX, clientY}) + const { component, editor } = buildComponent() + const { clientX, clientY } = clientPositionForCharacter( + component, + 1, + 16 + ) + component.didMouseDownOnContent({ + detail: 1, + button: 0, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 2, + button: 0, + clientX, + clientY + }) expect(editor.getSelectedScreenRange()).toEqual([[1, 13], [1, 21]]) expect(editor.testAutoscrollRequests).toEqual([]) }) it('selects lines on triple-click', () => { - const {component, editor} = buildComponent() - const {clientX, clientY} = clientPositionForCharacter(component, 1, 16) - component.didMouseDownOnContent({detail: 1, button: 0, clientX, clientY}) - component.didMouseDownOnContent({detail: 2, button: 0, clientX, clientY}) - component.didMouseDownOnContent({detail: 3, button: 0, clientX, clientY}) + const { component, editor } = buildComponent() + const { clientX, clientY } = clientPositionForCharacter( + component, + 1, + 16 + ) + component.didMouseDownOnContent({ + detail: 1, + button: 0, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 2, + button: 0, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 3, + button: 0, + clientX, + clientY + }) expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [2, 0]]) expect(editor.testAutoscrollRequests).toEqual([]) }) it('adds or removes cursors when holding cmd or ctrl when single-clicking', () => { - const {component, editor} = buildComponent({platform: 'darwin'}) + const { component, editor } = buildComponent({ platform: 'darwin' }) expect(editor.getCursorScreenPositions()).toEqual([[0, 0]]) // add cursor at 1, 16 @@ -3016,7 +4212,9 @@ describe('TextEditorComponent', () => { expect(editor.getCursorScreenPositions()).toEqual([[1, 16]]) // cmd-clicking within a selection destroys it - editor.addSelectionForScreenRange([[2, 10], [2, 15]], {autoscroll: false}) + editor.addSelectionForScreenRange([[2, 10], [2, 15]], { + autoscroll: false + }) expect(editor.getSelectedScreenRanges()).toEqual([ [[1, 16], [1, 16]], [[2, 10], [2, 15]] @@ -3028,9 +4226,7 @@ describe('TextEditorComponent', () => { metaKey: true }) ) - expect(editor.getSelectedScreenRanges()).toEqual([ - [[1, 16], [1, 16]] - ]) + expect(editor.getSelectedScreenRanges()).toEqual([[[1, 16], [1, 16]]]) // ctrl-click does not add cursors on macOS, nor does it move the cursor component.didMouseDownOnContent( @@ -3040,13 +4236,11 @@ describe('TextEditorComponent', () => { ctrlKey: true }) ) - expect(editor.getSelectedScreenRanges()).toEqual([ - [[1, 16], [1, 16]] - ]) + expect(editor.getSelectedScreenRanges()).toEqual([[[1, 16], [1, 16]]]) // ctrl-click adds cursors on platforms *other* than macOS component.props.platform = 'win32' - editor.setCursorScreenPosition([1, 4], {autoscroll: false}) + editor.setCursorScreenPosition([1, 4], { autoscroll: false }) component.didMouseDownOnContent( Object.assign(clientPositionForCharacter(component, 1, 16), { detail: 1, @@ -3060,8 +4254,8 @@ describe('TextEditorComponent', () => { }) it('adds word selections when holding cmd or ctrl when double-clicking', () => { - const {component, editor} = buildComponent() - editor.addCursorAtScreenPosition([1, 16], {autoscroll: false}) + const { component, editor } = buildComponent() + editor.addCursorAtScreenPosition([1, 16], { autoscroll: false }) expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]]) component.didMouseDownOnContent( @@ -3086,14 +4280,36 @@ describe('TextEditorComponent', () => { }) it('adds line selections when holding cmd or ctrl when triple-clicking', () => { - const {component, editor} = buildComponent() - editor.addCursorAtScreenPosition([1, 16], {autoscroll: false}) + const { component, editor } = buildComponent() + editor.addCursorAtScreenPosition([1, 16], { autoscroll: false }) expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]]) - const {clientX, clientY} = clientPositionForCharacter(component, 1, 16) - component.didMouseDownOnContent({detail: 1, button: 0, metaKey: true, clientX, clientY}) - component.didMouseDownOnContent({detail: 2, button: 0, metaKey: true, clientX, clientY}) - component.didMouseDownOnContent({detail: 3, button: 0, metaKey: true, clientX, clientY}) + const { clientX, clientY } = clientPositionForCharacter( + component, + 1, + 16 + ) + component.didMouseDownOnContent({ + detail: 1, + button: 0, + metaKey: true, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 2, + button: 0, + metaKey: true, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 3, + button: 0, + metaKey: true, + clientX, + clientY + }) expect(editor.getSelectedScreenRanges()).toEqual([ [[0, 0], [0, 0]], @@ -3103,73 +4319,111 @@ describe('TextEditorComponent', () => { }) it('expands the last selection on shift-click', () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() - editor.setCursorScreenPosition([2, 18], {autoscroll: false}) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 1, 4))) + editor.setCursorScreenPosition([2, 18], { autoscroll: false }) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 1, 4) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [2, 18]]) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 4, 4))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 4, 4) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[2, 18], [4, 4]]) // reorients word-wise selections to keep the word selected regardless of // where the subsequent shift-click occurs - editor.setCursorScreenPosition([2, 18], {autoscroll: false}) - editor.getLastSelection().selectWord({autoscroll: false}) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 1, 4))) + editor.setCursorScreenPosition([2, 18], { autoscroll: false }) + editor.getLastSelection().selectWord({ autoscroll: false }) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 1, 4) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[1, 2], [2, 20]]) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 3, 11))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 3, 11) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[2, 14], [3, 13]]) // reorients line-wise selections to keep the line selected regardless of // where the subsequent shift-click occurs - editor.setCursorScreenPosition([2, 18], {autoscroll: false}) - editor.getLastSelection().selectLine(null, {autoscroll: false}) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 1, 4))) + editor.setCursorScreenPosition([2, 18], { autoscroll: false }) + editor.getLastSelection().selectLine(null, { autoscroll: false }) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 1, 4) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]]) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 3, 11))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 3, 11) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[2, 0], [4, 0]]) expect(editor.testAutoscrollRequests).toEqual([]) }) it('expands the last selection on drag', () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - }, clientPositionForCharacter(component, 1, 4))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0 + }, + clientPositionForCharacter(component, 1, 4) + ) + ) { - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag(clientPositionForCharacter(component, 8, 8)) expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [8, 8]]) didDrag(clientPositionForCharacter(component, 4, 8)) @@ -3180,13 +4434,21 @@ describe('TextEditorComponent', () => { // Click-drag a second selection... selections are not merged until the // drag stops. - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - metaKey: 1, - }, clientPositionForCharacter(component, 8, 8))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + metaKey: 1 + }, + clientPositionForCharacter(component, 8, 8) + ) + ) { - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[1][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[1][0] didDrag(clientPositionForCharacter(component, 2, 8)) expect(editor.getSelectedScreenRanges()).toEqual([ [[1, 4], [4, 8]], @@ -3203,26 +4465,37 @@ describe('TextEditorComponent', () => { [[2, 8], [8, 8]] ]) didStopDragging() - expect(editor.getSelectedScreenRanges()).toEqual([ - [[1, 4], [8, 8]] - ]) + expect(editor.getSelectedScreenRanges()).toEqual([[[1, 4], [8, 8]]]) } }) it('expands the selection word-wise on double-click-drag', () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - }, clientPositionForCharacter(component, 1, 4))) - component.didMouseDownOnContent(Object.assign({ - detail: 2, - button: 0, - }, clientPositionForCharacter(component, 1, 4))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0 + }, + clientPositionForCharacter(component, 1, 4) + ) + ) + component.didMouseDownOnContent( + Object.assign( + { + detail: 2, + button: 0 + }, + clientPositionForCharacter(component, 1, 4) + ) + ) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[1][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[1][0] didDrag(clientPositionForCharacter(component, 0, 8)) expect(editor.getSelectedScreenRange()).toEqual([[0, 4], [1, 5]]) didDrag(clientPositionForCharacter(component, 2, 10)) @@ -3230,15 +4503,28 @@ describe('TextEditorComponent', () => { }) it('expands the selection line-wise on triple-click-drag', () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') - const tripleClickPosition = clientPositionForCharacter(component, 2, 8) - component.didMouseDownOnContent(Object.assign({detail: 1, button: 0}, tripleClickPosition)) - component.didMouseDownOnContent(Object.assign({detail: 2, button: 0}, tripleClickPosition)) - component.didMouseDownOnContent(Object.assign({detail: 3, button: 0}, tripleClickPosition)) + const tripleClickPosition = clientPositionForCharacter( + component, + 2, + 8 + ) + component.didMouseDownOnContent( + Object.assign({ detail: 1, button: 0 }, tripleClickPosition) + ) + component.didMouseDownOnContent( + Object.assign({ detail: 2, button: 0 }, tripleClickPosition) + ) + component.didMouseDownOnContent( + Object.assign({ detail: 3, button: 0 }, tripleClickPosition) + ) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[2][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[2][0] didDrag(clientPositionForCharacter(component, 1, 8)) expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]]) didDrag(clientPositionForCharacter(component, 4, 10)) @@ -3246,19 +4532,32 @@ describe('TextEditorComponent', () => { }) it('destroys folds when clicking on their fold markers', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.foldBufferRow(1) await component.getNextUpdatePromise() const target = element.querySelector('.fold-marker') - const {clientX, clientY} = clientPositionForCharacter(component, 1, editor.lineLengthForScreenRow(1)) - component.didMouseDownOnContent({detail: 1, button: 0, target, clientX, clientY}) + const { clientX, clientY } = clientPositionForCharacter( + component, + 1, + editor.lineLengthForScreenRow(1) + ) + component.didMouseDownOnContent({ + detail: 1, + button: 0, + target, + clientX, + clientY + }) expect(editor.isFoldedAtBufferRow(1)).toBe(false) expect(editor.getCursorScreenPosition()).toEqual([0, 0]) }) it('autoscrolls the content when dragging near the edge of the scroll container', async () => { - const {component, element, editor} = buildComponent({width: 200, height: 200}) + const { component, element, editor } = buildComponent({ + width: 200, + height: 200 + }) spyOn(component, 'handleMouseDragUntilMouseUp') let previousScrollTop = 0 @@ -3266,7 +4565,9 @@ describe('TextEditorComponent', () => { function assertScrolledDownAndRight () { expect(component.getScrollTop()).toBeGreaterThan(previousScrollTop) previousScrollTop = component.getScrollTop() - expect(component.getScrollLeft()).toBeGreaterThan(previousScrollLeft) + expect(component.getScrollLeft()).toBeGreaterThan( + previousScrollLeft + ) previousScrollLeft = component.getScrollLeft() } @@ -3277,26 +4578,46 @@ describe('TextEditorComponent', () => { previousScrollLeft = component.getScrollLeft() } - component.didMouseDownOnContent({detail: 1, button: 0, clientX: 100, clientY: 100}) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + component.didMouseDownOnContent({ + detail: 1, + button: 0, + clientX: 100, + clientY: 100 + }) + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDownAndRight() - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDownAndRight() - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDownAndRight() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUpAndLeft() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUpAndLeft() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUpAndLeft() // Don't artificially update scroll position beyond possible values expect(component.getScrollTop()).toBe(0) expect(component.getScrollLeft()).toBe(0) - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) expect(component.getScrollTop()).toBe(0) expect(component.getScrollLeft()).toBe(0) @@ -3305,22 +4626,25 @@ describe('TextEditorComponent', () => { setScrollTop(component, maxScrollTop) await setScrollLeft(component, maxScrollLeft) - didDrag({clientX: 199, clientY: 199}) - didDrag({clientX: 199, clientY: 199}) - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) + didDrag({ clientX: 199, clientY: 199 }) + didDrag({ clientX: 199, clientY: 199 }) expect(component.getScrollTop()).toBe(maxScrollTop) expect(component.getScrollLeft()).toBe(maxScrollLeft) }) }) it('pastes the previously selected text when clicking the middle mouse button on Linux', async () => { - spyOn(electron.ipcRenderer, 'send').andCallFake(function (eventName, selectedText) { + spyOn(electron.ipcRenderer, 'send').andCallFake(function ( + eventName, + selectedText + ) { if (eventName === 'write-text-to-selection-clipboard') { clipboard.writeText(selectedText, 'selection') } }) - const {component, editor} = buildComponent({platform: 'linux'}) + const { component, editor } = buildComponent({ platform: 'linux' }) // Middle mouse pasting. editor.setSelectedBufferRange([[1, 6], [1, 10]]) @@ -3352,13 +4676,19 @@ describe('TextEditorComponent', () => { }) it('does not paste into a read only editor when clicking the middle mouse button on Linux', async () => { - spyOn(electron.ipcRenderer, 'send').andCallFake(function (eventName, selectedText) { + spyOn(electron.ipcRenderer, 'send').andCallFake(function ( + eventName, + selectedText + ) { if (eventName === 'write-text-to-selection-clipboard') { clipboard.writeText(selectedText, 'selection') } }) - const {component, editor} = buildComponent({platform: 'linux', readOnly: true}) + const { component, editor } = buildComponent({ + platform: 'linux', + readOnly: true + }) // Select the word 'sort' on line 2 and copy to clipboard editor.setSelectedBufferRange([[1, 6], [1, 10]]) @@ -3379,7 +4709,7 @@ describe('TextEditorComponent', () => { describe('on the line number gutter', () => { it('selects all buffer rows intersecting the clicked screen row when a line number is clicked', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') editor.setSoftWrapped(true) await component.getNextUpdatePromise() @@ -3407,7 +4737,7 @@ describe('TextEditorComponent', () => { }) it('adds new selections when a line number is meta-clicked', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() editor.setSoftWrapped(true) await component.getNextUpdatePromise() @@ -3450,7 +4780,7 @@ describe('TextEditorComponent', () => { }) it('expands the last selection when a line number is shift-clicked', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') editor.setSoftWrapped(true) await component.getNextUpdatePromise() @@ -3473,7 +4803,10 @@ describe('TextEditorComponent', () => { ]) // Original selection is preserved when shift-click-dragging - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag({ clientY: clientTopForLine(component, 1) }) @@ -3487,13 +4820,11 @@ describe('TextEditorComponent', () => { }) didStopDragging() - expect(editor.getSelectedBufferRanges()).toEqual([ - [[2, 10], [8, 0]] - ]) + expect(editor.getSelectedBufferRanges()).toEqual([[[2, 10], [8, 0]]]) }) it('expands the selection when dragging', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') editor.setSoftWrapped(true) await component.getNextUpdatePromise() @@ -3510,7 +4841,10 @@ describe('TextEditorComponent', () => { clientY: clientTopForLine(component, 2) }) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag({ clientY: clientTopForLine(component, 1) @@ -3538,21 +4872,29 @@ describe('TextEditorComponent', () => { ]) didStopDragging() - expect(editor.getSelectedScreenRanges()).toEqual([ - [[2, 0], [4, 4]] - ]) + expect(editor.getSelectedScreenRanges()).toEqual([[[2, 0], [4, 4]]]) }) it('toggles folding when clicking on the right icon of a foldable line number', async () => { - const {component, element, editor} = buildComponent() - let target = element.querySelectorAll('.line-number')[1].querySelector('.icon-right') + const { component, element, editor } = buildComponent() + let target = element + .querySelectorAll('.line-number')[1] + .querySelector('.icon-right') expect(editor.isFoldedAtScreenRow(1)).toBe(false) - component.didMouseDownOnLineNumberGutter({target, button: 0, clientY: clientTopForLine(component, 1)}) + component.didMouseDownOnLineNumberGutter({ + target, + button: 0, + clientY: clientTopForLine(component, 1) + }) expect(editor.isFoldedAtScreenRow(1)).toBe(true) await component.getNextUpdatePromise() - component.didMouseDownOnLineNumberGutter({target, button: 0, clientY: clientTopForLine(component, 1)}) + component.didMouseDownOnLineNumberGutter({ + target, + button: 0, + clientY: clientTopForLine(component, 1) + }) await component.getNextUpdatePromise() expect(editor.isFoldedAtScreenRow(1)).toBe(false) @@ -3560,14 +4902,23 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise() expect(editor.isFoldedAtScreenRow(5)).toBe(true) - target = element.querySelectorAll('.line-number')[4].querySelector('.icon-right') - component.didMouseDownOnLineNumberGutter({target, button: 0, clientY: clientTopForLine(component, 4)}) + target = element + .querySelectorAll('.line-number')[4] + .querySelector('.icon-right') + component.didMouseDownOnLineNumberGutter({ + target, + button: 0, + clientY: clientTopForLine(component, 4) + }) expect(editor.isFoldedAtScreenRow(4)).toBe(false) }) it('autoscrolls when dragging near the top or bottom of the gutter', async () => { - const {component, editor} = buildComponent({width: 200, height: 200}) - const {scrollContainer} = component.refs + const { component, editor } = buildComponent({ + width: 200, + height: 200 + }) + const { scrollContainer } = component.refs spyOn(component, 'handleMouseDragUntilMouseUp') let previousScrollTop = 0 @@ -3586,26 +4937,46 @@ describe('TextEditorComponent', () => { previousScrollLeft = component.getScrollLeft() } - component.didMouseDownOnLineNumberGutter({detail: 1, button: 0, clientX: 0, clientY: 100}) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] - didDrag({clientX: 199, clientY: 199}) + component.didMouseDownOnLineNumberGutter({ + detail: 1, + button: 0, + clientX: 0, + clientY: 100 + }) + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDown() - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDown() - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDown() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUp() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUp() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUp() // Don't artificially update scroll measurements beyond the minimum or // maximum possible scroll positions expect(component.getScrollTop()).toBe(0) expect(component.getScrollLeft()).toBe(0) - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) expect(component.getScrollTop()).toBe(0) expect(component.getScrollLeft()).toBe(0) @@ -3614,9 +4985,9 @@ describe('TextEditorComponent', () => { setScrollTop(component, maxScrollTop) await setScrollLeft(component, maxScrollLeft) - didDrag({clientX: 199, clientY: 199}) - didDrag({clientX: 199, clientY: 199}) - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) + didDrag({ clientX: 199, clientY: 199 }) + didDrag({ clientX: 199, clientY: 199 }) expect(component.getScrollTop()).toBe(maxScrollTop) expect(component.getScrollLeft()).toBe(maxScrollLeft) }) @@ -3624,13 +4995,17 @@ describe('TextEditorComponent', () => { describe('on the scrollbars', () => { it('delegates the mousedown events to the parent component unless the mousedown was on the actual scrollbar', async () => { - const {component, element, editor} = buildComponent({height: 100}) + const { component, element, editor } = buildComponent({ height: 100 }) await setEditorWidthInCharacters(component, 6) const verticalScrollbar = component.refs.verticalScrollbar const horizontalScrollbar = component.refs.horizontalScrollbar - const leftEdgeOfVerticalScrollbar = verticalScrollbar.element.getBoundingClientRect().right - verticalScrollbarWidth - const topEdgeOfHorizontalScrollbar = horizontalScrollbar.element.getBoundingClientRect().bottom - horizontalScrollbarHeight + const leftEdgeOfVerticalScrollbar = + verticalScrollbar.element.getBoundingClientRect().right - + verticalScrollbarWidth + const topEdgeOfHorizontalScrollbar = + horizontalScrollbar.element.getBoundingClientRect().bottom - + horizontalScrollbarHeight verticalScrollbar.didMouseDown({ button: 0, @@ -3669,7 +5044,7 @@ describe('TextEditorComponent', () => { describe('paste event', () => { it("prevents the browser's default processing for the event on Linux", () => { - const {component} = buildComponent({platform: 'linux'}) + const { component } = buildComponent({ platform: 'linux' }) const event = { preventDefault: () => {} } spyOn(event, 'preventDefault') @@ -3680,194 +5055,293 @@ describe('TextEditorComponent', () => { describe('keyboard input', () => { it('handles inserted accented characters via the press-and-hold menu on macOS correctly', () => { - const {editor, component, element} = buildComponent({text: '', chromeVersion: 57}) + const { editor, component, element } = buildComponent({ + text: '', + chromeVersion: 57 + }) editor.insertText('x') editor.setCursorBufferPosition([0, 1]) // Simulate holding the A key to open the press-and-hold menu, // then closing it via ESC. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'Escape'}) - component.didKeyup({code: 'Escape'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'Escape' }) + component.didKeyup({ code: 'Escape' }) expect(editor.getText()).toBe('xa') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xaa') editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // then selecting an alternative by typing a number. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'Digit2'}) - component.didKeyup({code: 'Digit2'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'Digit2' }) + component.didKeyup({ code: 'Digit2' }) + component.didTextInput({ + data: 'á', + stopPropagation: () => {}, + preventDefault: () => {} + }) expect(editor.getText()).toBe('xá') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xáa') editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // then selecting an alternative by clicking on it. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didTextInput({ + data: 'á', + stopPropagation: () => {}, + preventDefault: () => {} + }) expect(editor.getText()).toBe('xá') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xáa') editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // cycling through the alternatives with the arrows, then selecting one of them with Enter. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionStart({ data: '' }) + component.didCompositionUpdate({ data: 'à' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionUpdate({ data: 'á' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xá') - component.didKeydown({code: 'Enter'}) - component.didCompositionUpdate({data: 'á'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'á', target: component.refs.cursorsAndInput.refs.hiddenInput}) - component.didKeyup({code: 'Enter'}) + component.didKeydown({ code: 'Enter' }) + component.didCompositionUpdate({ data: 'á' }) + component.didTextInput({ + data: 'á', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didCompositionEnd({ + data: 'á', + target: component.refs.cursorsAndInput.refs.hiddenInput + }) + component.didKeyup({ code: 'Enter' }) expect(editor.getText()).toBe('xá') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xáa') editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // cycling through the alternatives with the arrows, then closing it via ESC. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionStart({ data: '' }) + component.didCompositionUpdate({ data: 'à' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionUpdate({ data: 'á' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xá') - component.didKeydown({code: 'Escape'}) - component.didCompositionUpdate({data: 'a'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) - component.didKeyup({code: 'Escape'}) + component.didKeydown({ code: 'Escape' }) + component.didCompositionUpdate({ data: 'a' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didCompositionEnd({ + data: 'a', + target: component.refs.cursorsAndInput.refs.hiddenInput + }) + component.didKeyup({ code: 'Escape' }) expect(editor.getText()).toBe('xa') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xaa') editor.undo() expect(editor.getText()).toBe('x') // Simulate pressing the O key and holding the A key to open the press-and-hold menu right before releasing the O key, // cycling through the alternatives with the arrows, then closing it via ESC. - component.didKeydown({code: 'KeyO'}) - component.didKeypress({code: 'KeyO'}) - component.didTextInput({data: 'o', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyO'}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'KeyO' }) + component.didKeypress({ code: 'KeyO' }) + component.didTextInput({ + data: 'o', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyO' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionStart({ data: '' }) + component.didCompositionUpdate({ data: 'à' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xoà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionUpdate({ data: 'á' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xoá') - component.didKeydown({code: 'Escape'}) - component.didCompositionUpdate({data: 'a'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) - component.didKeyup({code: 'Escape'}) + component.didKeydown({ code: 'Escape' }) + component.didCompositionUpdate({ data: 'a' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didCompositionEnd({ + data: 'a', + target: component.refs.cursorsAndInput.refs.hiddenInput + }) + component.didKeyup({ code: 'Escape' }) expect(editor.getText()).toBe('xoa') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // cycling through the alternatives with the arrows, then closing it by changing focus. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionStart({ data: '' }) + component.didCompositionUpdate({ data: 'à' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionUpdate({ data: 'á' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xá') - component.didCompositionUpdate({data: 'á'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'á', target: component.refs.cursorsAndInput.refs.hiddenInput}) + component.didCompositionUpdate({ data: 'á' }) + component.didTextInput({ + data: 'á', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didCompositionEnd({ + data: 'á', + target: component.refs.cursorsAndInput.refs.hiddenInput + }) expect(editor.getText()).toBe('xá') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xáa') editor.undo() expect(editor.getText()).toBe('x') @@ -3876,9 +5350,12 @@ describe('TextEditorComponent', () => { describe('styling changes', () => { it('updates the rendered content based on new measurements when the font dimensions change', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 1, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 1, + autoHeight: false + }) await setEditorHeightInLines(component, 3) - editor.setCursorScreenPosition([1, 29], {autoscroll: false}) + editor.setCursorScreenPosition([1, 29], { autoscroll: false }) await component.getNextUpdatePromise() let cursorNode = element.querySelector('.cursor') @@ -3901,26 +5378,49 @@ describe('TextEditorComponent', () => { element.style.fontSize = initialFontSize - 5 + 'px' TextEditor.didUpdateStyles() await component.getNextUpdatePromise() - expect(editor.getDefaultCharWidth()).toBeLessThan(initialBaseCharacterWidth) - expect(editor.getDoubleWidthCharWidth()).toBeLessThan(initialDoubleCharacterWidth) - expect(editor.getHalfWidthCharWidth()).toBeLessThan(initialHalfCharacterWidth) - expect(editor.getKoreanCharWidth()).toBeLessThan(initialKoreanCharacterWidth) - expect(queryOnScreenLineElements(element).length).toBeGreaterThan(initialRenderedLineCount) + expect(editor.getDefaultCharWidth()).toBeLessThan( + initialBaseCharacterWidth + ) + expect(editor.getDoubleWidthCharWidth()).toBeLessThan( + initialDoubleCharacterWidth + ) + expect(editor.getHalfWidthCharWidth()).toBeLessThan( + initialHalfCharacterWidth + ) + expect(editor.getKoreanCharWidth()).toBeLessThan( + initialKoreanCharacterWidth + ) + expect(queryOnScreenLineElements(element).length).toBeGreaterThan( + initialRenderedLineCount + ) verifyCursorPosition(component, cursorNode, 1, 29) element.style.fontSize = initialFontSize + 10 + 'px' TextEditor.didUpdateStyles() await component.getNextUpdatePromise() - expect(editor.getDefaultCharWidth()).toBeGreaterThan(initialBaseCharacterWidth) - expect(editor.getDoubleWidthCharWidth()).toBeGreaterThan(initialDoubleCharacterWidth) - expect(editor.getHalfWidthCharWidth()).toBeGreaterThan(initialHalfCharacterWidth) - expect(editor.getKoreanCharWidth()).toBeGreaterThan(initialKoreanCharacterWidth) - expect(queryOnScreenLineElements(element).length).toBeLessThan(initialRenderedLineCount) + expect(editor.getDefaultCharWidth()).toBeGreaterThan( + initialBaseCharacterWidth + ) + expect(editor.getDoubleWidthCharWidth()).toBeGreaterThan( + initialDoubleCharacterWidth + ) + expect(editor.getHalfWidthCharWidth()).toBeGreaterThan( + initialHalfCharacterWidth + ) + expect(editor.getKoreanCharWidth()).toBeGreaterThan( + initialKoreanCharacterWidth + ) + expect(queryOnScreenLineElements(element).length).toBeLessThan( + initialRenderedLineCount + ) verifyCursorPosition(component, cursorNode, 1, 29) }) it('maintains the scrollTopRow and scrollLeftColumn when the font size changes', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 1, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 1, + autoHeight: false + }) await setEditorHeightInLines(component, 3) await setEditorWidthInCharacters(component, 20) component.setScrollTopRow(4) @@ -3940,19 +5440,25 @@ describe('TextEditorComponent', () => { }) it('gracefully handles the editor being hidden after a styling change', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) - element.style.fontSize = parseInt(getComputedStyle(element).fontSize) + 5 + 'px' + const { component, element, editor } = buildComponent({ + autoHeight: false + }) + element.style.fontSize = + parseInt(getComputedStyle(element).fontSize) + 5 + 'px' TextEditor.didUpdateStyles() element.style.display = 'none' await component.getNextUpdatePromise() }) it('does not throw an exception when the editor is soft-wrapped and changing the font size changes also the longest screen line', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) editor.setText( 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do\n' + - 'eiusmod tempor incididunt ut labore et dolore magna' + - 'aliqua. Ut enim ad minim veniam, quis nostrud exercitation' + 'eiusmod tempor incididunt ut labore et dolore magna' + + 'aliqua. Ut enim ad minim veniam, quis nostrud exercitation' ) editor.setSoftWrapped(true) await setEditorHeightInLines(component, 2) @@ -3965,12 +5471,15 @@ describe('TextEditorComponent', () => { }) it('updates the width of the lines div based on the longest screen line', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 1, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 1, + autoHeight: false + }) editor.setText( 'Lorem ipsum dolor sit\n' + - 'amet, consectetur adipisicing\n' + - 'elit, sed do\n' + - 'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation' + 'amet, consectetur adipisicing\n' + + 'elit, sed do\n' + + 'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation' ) await setEditorHeightInLines(component, 2) @@ -3983,7 +5492,7 @@ describe('TextEditorComponent', () => { const actualWidth = element.querySelector('.lines').style.width const expectedWidth = Math.ceil( component.pixelPositionForScreenPosition(Point(3, Infinity)).left + - component.getBaseCharacterWidth() + component.getBaseCharacterWidth() ) expect(actualWidth).toBe(expectedWidth + 'px') }) @@ -3993,26 +5502,36 @@ describe('TextEditorComponent', () => { let editorElementWasUpdatedSynchronously beforeEach(() => { - editorElementWasUpdatedSynchronously = TextEditorElement.prototype.updatedSynchronously + editorElementWasUpdatedSynchronously = + TextEditorElement.prototype.updatedSynchronously }) afterEach(() => { - TextEditorElement.prototype.setUpdatedSynchronously(editorElementWasUpdatedSynchronously) + TextEditorElement.prototype.setUpdatedSynchronously( + editorElementWasUpdatedSynchronously + ) }) it('updates synchronously when updatedSynchronously is true', () => { const editor = buildEditor() - const {element} = new TextEditorComponent({model: editor, updatedSynchronously: true}) + const { element } = new TextEditorComponent({ + model: editor, + updatedSynchronously: true + }) jasmine.attachToDOM(element) editor.setText('Lorem ipsum dolor') - expect(queryOnScreenLineElements(element).map(l => l.textContent)).toEqual([ - editor.lineTextForScreenRow(0) - ]) + expect( + queryOnScreenLineElements(element).map(l => l.textContent) + ).toEqual([editor.lineTextForScreenRow(0)]) }) it('does not throw an exception on attachment when setting the soft-wrap column', () => { - const {component, element, editor} = buildComponent({width: 435, attach: false, updatedSynchronously: true}) + const { component, element, editor } = buildComponent({ + width: 435, + attach: false, + updatedSynchronously: true + }) editor.setSoftWrapped(true) spyOn(window, 'onerror').andCallThrough() jasmine.attachToDOM(element) // should not throw an exception @@ -4026,14 +5545,14 @@ describe('TextEditorComponent', () => { jasmine.attachToDOM(element) editor.setText('Lorem ipsum dolor') - expect(queryOnScreenLineElements(element).map(l => l.textContent)).toEqual([ - editor.lineTextForScreenRow(0) - ]) + expect( + queryOnScreenLineElements(element).map(l => l.textContent) + ).toEqual([editor.lineTextForScreenRow(0)]) }) it('measures dimensions synchronously when measureDimensions is called on the component', () => { TextEditorElement.prototype.setUpdatedSynchronously(true) - const editor = buildEditor({autoHeight: false}) + const editor = buildEditor({ autoHeight: false }) const element = editor.element jasmine.attachToDOM(element) @@ -4046,62 +5565,113 @@ describe('TextEditorComponent', () => { describe('pixelPositionForScreenPosition(point)', () => { it('returns the pixel position for the given point, regardless of whether or not it is currently on screen', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 3) await setScrollTop(component, 3 * component.getLineHeight()) - const {component: referenceComponent} = buildComponent() + const { component: referenceComponent } = buildComponent() const referenceContentRect = referenceComponent.refs.content.getBoundingClientRect() { - const {top, left} = component.pixelPositionForScreenPosition({row: 0, column: 0}) - expect(top).toBe(clientTopForLine(referenceComponent, 0) - referenceContentRect.top) - expect(left).toBe(clientLeftForCharacter(referenceComponent, 0, 0) - referenceContentRect.left) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 0, + column: 0 + }) + expect(top).toBe( + clientTopForLine(referenceComponent, 0) - referenceContentRect.top + ) + expect(left).toBe( + clientLeftForCharacter(referenceComponent, 0, 0) - + referenceContentRect.left + ) } { - const {top, left} = component.pixelPositionForScreenPosition({row: 0, column: 5}) - expect(top).toBe(clientTopForLine(referenceComponent, 0) - referenceContentRect.top) - expect(left).toBe(clientLeftForCharacter(referenceComponent, 0, 5) - referenceContentRect.left) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 0, + column: 5 + }) + expect(top).toBe( + clientTopForLine(referenceComponent, 0) - referenceContentRect.top + ) + expect(left).toBe( + clientLeftForCharacter(referenceComponent, 0, 5) - + referenceContentRect.left + ) } { - const {top, left} = component.pixelPositionForScreenPosition({row: 12, column: 1}) - expect(top).toBe(clientTopForLine(referenceComponent, 12) - referenceContentRect.top) - expect(left).toBe(clientLeftForCharacter(referenceComponent, 12, 1) - referenceContentRect.left) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 12, + column: 1 + }) + expect(top).toBe( + clientTopForLine(referenceComponent, 12) - referenceContentRect.top + ) + expect(left).toBe( + clientLeftForCharacter(referenceComponent, 12, 1) - + referenceContentRect.left + ) } // Measuring a currently rendered line while an autoscroll that causes // that line to go off-screen is in progress. { editor.setCursorScreenPosition([10, 0]) - const {top, left} = component.pixelPositionForScreenPosition({row: 3, column: 5}) - expect(top).toBe(clientTopForLine(referenceComponent, 3) - referenceContentRect.top) - expect(left).toBe(clientLeftForCharacter(referenceComponent, 3, 5) - referenceContentRect.left) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 3, + column: 5 + }) + expect(top).toBe( + clientTopForLine(referenceComponent, 3) - referenceContentRect.top + ) + expect(left).toBe( + clientLeftForCharacter(referenceComponent, 3, 5) - + referenceContentRect.left + ) } }) it('does not get the component into an inconsistent state when the model has unflushed changes (regression)', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false, text: ''}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false, + text: '' + }) await setEditorHeightInLines(component, 10) - const updatePromise = editor.getBuffer().append("hi\n") - component.screenPositionForPixelPosition({top: 800, left: 1}) + const updatePromise = editor.getBuffer().append('hi\n') + component.screenPositionForPixelPosition({ top: 800, left: 1 }) await updatePromise }) it('does not shift cursors downward or render off-screen content when measuring off-screen lines (regression)', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 3) - const {top, left} = component.pixelPositionForScreenPosition({row: 12, column: 1}) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 12, + column: 1 + }) - expect(element.querySelector('.cursor').getBoundingClientRect().top).toBe(component.refs.lineTiles.getBoundingClientRect().top) - expect(element.querySelector('.line[data-screen-row="12"]').style.visibility).toBe('hidden') + expect(element.querySelector('.cursor').getBoundingClientRect().top).toBe( + component.refs.lineTiles.getBoundingClientRect().top + ) + expect( + element.querySelector('.line[data-screen-row="12"]').style.visibility + ).toBe('hidden') // Ensure previously measured off screen lines don't have any weird // styling when they come on screen in the next frame await setEditorHeightInLines(component, 13) - const previouslyMeasuredLineElement = element.querySelector('.line[data-screen-row="12"]') + const previouslyMeasuredLineElement = element.querySelector( + '.line[data-screen-row="12"]' + ) expect(previouslyMeasuredLineElement.style.display).toBe('') expect(previouslyMeasuredLineElement.style.visibility).toBe('') }) @@ -4109,54 +5679,79 @@ describe('TextEditorComponent', () => { describe('screenPositionForPixelPosition', () => { it('returns the screen position for the given pixel position, regardless of whether or not it is currently on screen', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 3) await setScrollTop(component, 3 * component.getLineHeight()) - const {component: referenceComponent} = buildComponent() + const { component: referenceComponent } = buildComponent() { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 0, column: 0}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 0, column: 0 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([0, 0]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [0, 0] + ) } { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 0, column: 5}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 0, column: 5 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([0, 5]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [0, 5] + ) } { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 5, column: 7}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 5, column: 7 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([5, 7]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [5, 7] + ) } { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 12, column: 1}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 12, column: 1 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([12, 1]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [12, 1] + ) } // Measuring a currently rendered line while an autoscroll that causes // that line to go off-screen is in progress. { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 3, column: 4}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 3, column: 4 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 editor.setCursorBufferPosition([10, 0]) - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([3, 4]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [3, 4] + ) } }) }) describe('model methods that delegate to the component / element', () => { it('delegates setHeight and getHeight to the component', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) + const { component, element, editor } = buildComponent({ + autoHeight: false + }) spyOn(Grim, 'deprecate') expect(editor.getHeight()).toBe(component.getScrollContainerHeight()) expect(Grim.deprecate.callCount).toBe(1) @@ -4168,7 +5763,7 @@ describe('TextEditorComponent', () => { }) it('delegates setWidth and getWidth to the component', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() spyOn(Grim, 'deprecate') expect(editor.getWidth()).toBe(component.getScrollContainerWidth()) expect(Grim.deprecate.callCount).toBe(1) @@ -4180,42 +5775,67 @@ describe('TextEditorComponent', () => { }) it('delegates getFirstVisibleScreenRow, getLastVisibleScreenRow, and getVisibleRowRange to the component', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) element.style.height = 4 * component.measurements.lineHeight + 'px' await component.getNextUpdatePromise() await setScrollTop(component, 5 * component.getLineHeight()) - expect(editor.getFirstVisibleScreenRow()).toBe(component.getFirstVisibleRow()) - expect(editor.getLastVisibleScreenRow()).toBe(component.getLastVisibleRow()) - expect(editor.getVisibleRowRange()).toEqual([component.getFirstVisibleRow(), component.getLastVisibleRow()]) + expect(editor.getFirstVisibleScreenRow()).toBe( + component.getFirstVisibleRow() + ) + expect(editor.getLastVisibleScreenRow()).toBe( + component.getLastVisibleRow() + ) + expect(editor.getVisibleRowRange()).toEqual([ + component.getFirstVisibleRow(), + component.getLastVisibleRow() + ]) }) it('assigns scrollTop on the component when calling setFirstVisibleScreenRow', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) - element.style.height = 4 * component.measurements.lineHeight + horizontalScrollbarHeight + 'px' + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) + element.style.height = + 4 * component.measurements.lineHeight + horizontalScrollbarHeight + 'px' await component.getNextUpdatePromise() expect(component.getMaxScrollTop() / component.getLineHeight()).toBe(9) - expect(component.refs.verticalScrollbar.element.scrollTop).toBe(0 * component.getLineHeight()) + expect(component.refs.verticalScrollbar.element.scrollTop).toBe( + 0 * component.getLineHeight() + ) editor.setFirstVisibleScreenRow(1) expect(component.getFirstVisibleRow()).toBe(1) await component.getNextUpdatePromise() - expect(component.refs.verticalScrollbar.element.scrollTop).toBe(1 * component.getLineHeight()) + expect(component.refs.verticalScrollbar.element.scrollTop).toBe( + 1 * component.getLineHeight() + ) editor.setFirstVisibleScreenRow(5) expect(component.getFirstVisibleRow()).toBe(5) await component.getNextUpdatePromise() - expect(component.refs.verticalScrollbar.element.scrollTop).toBe(5 * component.getLineHeight()) + expect(component.refs.verticalScrollbar.element.scrollTop).toBe( + 5 * component.getLineHeight() + ) editor.setFirstVisibleScreenRow(11) expect(component.getFirstVisibleRow()).toBe(9) await component.getNextUpdatePromise() - expect(component.refs.verticalScrollbar.element.scrollTop).toBe(9 * component.getLineHeight()) + expect(component.refs.verticalScrollbar.element.scrollTop).toBe( + 9 * component.getLineHeight() + ) }) it('delegates setFirstVisibleScreenColumn and getFirstVisibleScreenColumn to the component', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) element.style.width = 30 * component.getBaseCharacterWidth() + 'px' await component.getNextUpdatePromise() expect(editor.getFirstVisibleScreenColumn()).toBe(0) @@ -4224,27 +5844,38 @@ describe('TextEditorComponent', () => { setScrollLeft(component, 5.5 * component.getBaseCharacterWidth()) expect(editor.getFirstVisibleScreenColumn()).toBe(5) await component.getNextUpdatePromise() - expect(component.refs.horizontalScrollbar.element.scrollLeft).toBeCloseTo(5.5 * component.getBaseCharacterWidth(), -1) + expect(component.refs.horizontalScrollbar.element.scrollLeft).toBeCloseTo( + 5.5 * component.getBaseCharacterWidth(), + -1 + ) editor.setFirstVisibleScreenColumn(12) - expect(component.getScrollLeft()).toBeCloseTo(12 * component.getBaseCharacterWidth(), -1) + expect(component.getScrollLeft()).toBeCloseTo( + 12 * component.getBaseCharacterWidth(), + -1 + ) await component.getNextUpdatePromise() - expect(component.refs.horizontalScrollbar.element.scrollLeft).toBeCloseTo(12 * component.getBaseCharacterWidth(), -1) + expect(component.refs.horizontalScrollbar.element.scrollLeft).toBeCloseTo( + 12 * component.getBaseCharacterWidth(), + -1 + ) }) }) describe('handleMouseDragUntilMouseUp', () => { it('repeatedly schedules `didDrag` calls on new animation frames after moving the mouse, and calls `didStopDragging` on mouseup', async () => { - const {component} = buildComponent() + const { component } = buildComponent() let dragEvents let dragging = false component.handleMouseDragUntilMouseUp({ - didDrag: (event) => { + didDrag: event => { dragging = true dragEvents.push(event) }, - didStopDragging: () => { dragging = false } + didStopDragging: () => { + dragging = false + } }) expect(dragging).toBe(false) @@ -4282,13 +5913,17 @@ describe('TextEditorComponent', () => { }) it('calls `didStopDragging` if the user interacts with the keyboard while dragging', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() let dragging = false function startDragging () { component.handleMouseDragUntilMouseUp({ - didDrag: (event) => { dragging = true }, - didStopDragging: () => { dragging = false } + didDrag: event => { + dragging = true + }, + didStopDragging: () => { + dragging = false + } }) } @@ -4302,7 +5937,7 @@ describe('TextEditorComponent', () => { expect(dragging).toBe(true) // Keyboard interaction prevents users from dragging further. - component.didKeydown({code: 'KeyX'}) + component.didKeydown({ code: 'KeyX' }) expect(dragging).toBe(false) window.dispatchEvent(new MouseEvent('mousemove')) @@ -4314,31 +5949,42 @@ describe('TextEditorComponent', () => { window.dispatchEvent(new MouseEvent('mousemove')) await getNextAnimationFramePromise() expect(dragging).toBe(true) - component.didKeydown({key: 'Control'}) - component.didKeydown({key: 'Alt'}) - component.didKeydown({key: 'Shift'}) - component.didKeydown({key: 'Meta'}) + component.didKeydown({ key: 'Control' }) + component.didKeydown({ key: 'Alt' }) + component.didKeydown({ key: 'Shift' }) + component.didKeydown({ key: 'Meta' }) expect(dragging).toBe(true) }) function getNextAnimationFramePromise () { - return new Promise((resolve) => requestAnimationFrame(resolve)) + return new Promise(resolve => requestAnimationFrame(resolve)) } }) }) function buildEditor (params = {}) { const text = params.text != null ? params.text : SAMPLE_TEXT - const buffer = new TextBuffer({text}) - const editorParams = {buffer, readOnly: params.readOnly} + const buffer = new TextBuffer({ text }) + const editorParams = { buffer, readOnly: params.readOnly } if (params.height != null) params.autoHeight = false - for (const paramName of ['mini', 'autoHeight', 'autoWidth', 'lineNumberGutterVisible', 'showLineNumbers', 'placeholderText', 'softWrapped', 'scrollSensitivity']) { + for (const paramName of [ + 'mini', + 'autoHeight', + 'autoWidth', + 'lineNumberGutterVisible', + 'showLineNumbers', + 'placeholderText', + 'softWrapped', + 'scrollSensitivity' + ]) { if (params[paramName] != null) editorParams[paramName] = params[paramName] } atom.grammars.autoAssignLanguageMode(buffer) const editor = new TextEditor(editorParams) editor.testAutoscrollRequests = [] - editor.onDidRequestAutoscroll((request) => { editor.testAutoscrollRequests.push(request) }) + editor.onDidRequestAutoscroll(request => { + editor.testAutoscrollRequests.push(request) + }) editors.push(editor) return editor } @@ -4352,7 +5998,7 @@ function buildComponent (params = {}) { platform: params.platform, chromeVersion: params.chromeVersion }) - const {element} = component + const { element } = component if (!editor.getAutoHeight()) { element.style.height = params.height ? params.height + 'px' : '600px' } @@ -4360,15 +6006,18 @@ function buildComponent (params = {}) { element.style.width = params.width ? params.width + 'px' : '800px' } if (params.attach !== false) jasmine.attachToDOM(element) - return {component, element, editor} + return { component, element, editor } } function getEditorWidthInBaseCharacters (component) { - return Math.round(component.getScrollContainerWidth() / component.getBaseCharacterWidth()) + return Math.round( + component.getScrollContainerWidth() / component.getBaseCharacterWidth() + ) } -async function setEditorHeightInLines(component, heightInLines) { - component.element.style.height = component.getLineHeight() * heightInLines + 'px' +async function setEditorHeightInLines (component, heightInLines) { + component.element.style.height = + component.getLineHeight() * heightInLines + 'px' await component.getNextUpdatePromise() } @@ -4384,7 +6033,9 @@ async function setEditorWidthInCharacters (component, widthInCharacters) { function verifyCursorPosition (component, cursorNode, row, column) { const rect = cursorNode.getBoundingClientRect() expect(Math.round(rect.top)).toBe(clientTopForLine(component, row)) - expect(Math.round(rect.left)).toBe(Math.round(clientLeftForCharacter(component, row, column))) + expect(Math.round(rect.left)).toBe( + Math.round(clientLeftForCharacter(component, row, column)) + ) } function clientTopForLine (component, row) { @@ -4420,7 +6071,8 @@ function clientPositionForCharacter (component, row, column) { } function lineNumberNodeForScreenRow (component, row) { - const gutterElement = component.refs.gutterContainer.refs.lineNumberGutter.element + const gutterElement = + component.refs.gutterContainer.refs.lineNumberGutter.element const tileStartRow = component.tileStartRowForRow(row) const tileIndex = component.renderedTileStartRows.indexOf(tileStartRow) return gutterElement.children[tileIndex + 1].children[row - tileStartRow] @@ -4428,7 +6080,8 @@ function lineNumberNodeForScreenRow (component, row) { function lineNodeForScreenRow (component, row) { const renderedScreenLine = component.renderedScreenLineForRow(row) - return component.lineComponentsByScreenLineId.get(renderedScreenLine.id).element + return component.lineComponentsByScreenLineId.get(renderedScreenLine.id) + .element } function textNodesForScreenRow (component, row) { @@ -4486,7 +6139,7 @@ function getElementHeight (element) { } function getNextTickPromise () { - return new Promise((resolve) => process.nextTick(resolve)) + return new Promise(resolve => process.nextTick(resolve)) } function queryOnScreenLineNumberElements (element) { @@ -4494,5 +6147,7 @@ function queryOnScreenLineNumberElements (element) { } function queryOnScreenLineElements (element) { - return Array.from(element.querySelectorAll('.line:not(.dummy):not([data-off-screen])')) + return Array.from( + element.querySelectorAll('.line:not(.dummy):not([data-off-screen])') + ) } diff --git a/spec/text-editor-element-spec.js b/spec/text-editor-element-spec.js index d6c33e7ad..b22d2c782 100644 --- a/spec/text-editor-element-spec.js +++ b/spec/text-editor-element-spec.js @@ -1,4 +1,13 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach, + conditionPromise, + timeoutPromise +} = require('./async-spec-helpers') const TextEditor = require('../src/text-editor') const TextEditorElement = require('../src/text-editor-element') @@ -9,7 +18,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 +63,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 +80,8 @@ describe('TextEditorElement', () => { expect(element.getModel().isLineNumberGutterVisible()).toBe(false) }) - it("honors the 'readonly' attribute", async function() { - jasmineContent.innerHTML = "" + it("honors the 'readonly' attribute", async function () { + jasmineContent.innerHTML = '' const element = jasmineContent.firstChild expect(element.getComponent().isInputEnabled()).toBe(false) @@ -108,11 +118,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 +134,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 +153,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 +208,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 +232,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 +254,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 +267,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 +278,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 +293,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 +310,7 @@ describe('TextEditorElement', () => { expect(attachedCallback).not.toHaveBeenCalled() expect(detachedCallback).toHaveBeenCalled() - }) - ) + })) describe('::setUpdatedSynchronously', () => { it('controls whether the text editor is updated synchronously', () => { @@ -318,7 +335,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 +358,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 +371,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}) + element.getModel().update({ autoHeight: false }) element.getModel().setText('lorem\nipsum\ndolor\nsit\namet') element.setHeight(20) await element.getNextUpdatePromise() @@ -387,8 +403,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 +411,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 +434,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 +460,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 +471,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 +492,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 +518,6 @@ describe('TextEditorElement', () => { positions.length = 0 element.setScrollLeft(30) expect(positions).toEqual([30]) - }) - ) + })) }) }) diff --git a/spec/text-editor-registry-spec.js b/spec/text-editor-registry-spec.js index 4c6d680eb..c6303e4fd 100644 --- a/spec/text-editor-registry-spec.js +++ b/spec/text-editor-registry-spec.js @@ -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, fit, ffit, fffit } = 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,7 +281,7 @@ 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') @@ -282,11 +306,14 @@ describe('TextEditorRegistry', function () { 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) @@ -335,7 +362,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 +379,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 +392,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 +405,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 +418,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 +441,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 +454,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 +467,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 +484,7 @@ describe('TextEditorRegistry', function () { softWrapped: true, preferredLineLength: 80, editorWidthInChars: 120, - softWrapAtPreferredLineLength: true, + softWrapAtPreferredLineLength: true }) expect(editor.getSoftWrapColumn()).toBe(80) @@ -475,7 +502,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 +515,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 +528,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 +541,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 +554,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 +567,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 +580,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 +594,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 +616,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) { diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 908ea8082..60c8076df 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -1,10 +1,19 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach, + conditionPromise, + timeoutPromise +} = require('./async-spec-helpers') const fs = require('fs') const path = require('path') const temp = require('temp').track() const dedent = require('dedent') -const {clipboard} = require('electron') +const { clipboard } = require('electron') const TextEditor = require('../src/text-editor') const TextBuffer = require('text-buffer') const TextMateLanguageMode = require('../src/text-mate-language-mode') @@ -16,7 +25,7 @@ describe('TextEditor', () => { beforeEach(async () => { editor = await atom.workspace.open('sample.js') buffer = editor.buffer - editor.update({autoIndent: false}) + editor.update({ autoIndent: false }) lineLengths = buffer.getLines().map(line => line.length) await atom.packages.activatePackage('language-javascript') }) @@ -24,8 +33,8 @@ describe('TextEditor', () => { it('generates unique ids for each editor', async () => { // Deserialized editors are initialized with the serialized id. We can // initialize an editor with what we expect to be the next id: - const deserialized = new TextEditor({id: editor.id+1}) - expect(deserialized.id).toEqual(editor.id+1) + const deserialized = new TextEditor({ id: editor.id + 1 }) + expect(deserialized.id).toEqual(editor.id + 1) // The id generator should skip the id used up by the deserialized one: const fresh = new TextEditor() @@ -35,7 +44,7 @@ describe('TextEditor', () => { describe('when the editor is deserialized', () => { it('restores selections and folds based on markers in the buffer', async () => { editor.setSelectedBufferRange([[1, 2], [3, 4]]) - editor.addSelectionForBufferRange([[5, 6], [7, 5]], {reversed: true}) + editor.addSelectionForBufferRange([[5, 6], [7, 5]], { reversed: true }) editor.foldBufferRow(4) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -43,12 +52,19 @@ describe('TextEditor', () => { const editor2 = TextEditor.deserialize(editor.serialize(), { assert: atom.assert, textEditors: atom.textEditors, - project: {bufferForIdSync () { return buffer2 }} + project: { + bufferForIdSync () { + return buffer2 + } + } }) expect(editor2.id).toBe(editor.id) expect(editor2.getBuffer().getPath()).toBe(editor.getBuffer().getPath()) - expect(editor2.getSelectedBufferRanges()).toEqual([[[1, 2], [3, 4]], [[5, 6], [7, 5]]]) + expect(editor2.getSelectedBufferRanges()).toEqual([ + [[1, 2], [3, 4]], + [[5, 6], [7, 5]] + ]) expect(editor2.getSelections()[1].isReversed()).toBeTruthy() expect(editor2.isFoldedAtBufferRow(4)).toBeTruthy() editor2.destroy() @@ -62,7 +78,7 @@ describe('TextEditor', () => { softWrapped: true, softWrapAtPreferredLineLength: true, softWrapHangingIndentLength: 8, - invisibles: {space: 'S'}, + invisibles: { space: 'S' }, showInvisibles: true, editorWidthInChars: 120 }) @@ -73,25 +89,39 @@ describe('TextEditor', () => { const editor2 = TextEditor.deserialize(editor.serialize(), { assert: atom.assert, textEditors: atom.textEditors, - project: {bufferForIdSync () { return buffer2 }} + project: { + bufferForIdSync () { + return buffer2 + } + } }) expect(editor2.getSoftTabs()).toBe(editor.getSoftTabs()) expect(editor2.hasAtomicSoftTabs()).toBe(editor.hasAtomicSoftTabs()) expect(editor2.getTabLength()).toBe(editor.getTabLength()) expect(editor2.getSoftWrapColumn()).toBe(editor.getSoftWrapColumn()) - expect(editor2.getSoftWrapHangingIndentLength()).toBe(editor.getSoftWrapHangingIndentLength()) + expect(editor2.getSoftWrapHangingIndentLength()).toBe( + editor.getSoftWrapHangingIndentLength() + ) expect(editor2.getInvisibles()).toEqual(editor.getInvisibles()) - expect(editor2.getEditorWidthInChars()).toBe(editor.getEditorWidthInChars()) + expect(editor2.getEditorWidthInChars()).toBe( + editor.getEditorWidthInChars() + ) expect(editor2.displayLayer.tabLength).toBe(editor2.getTabLength()) - expect(editor2.displayLayer.softWrapColumn).toBe(editor2.getSoftWrapColumn()) + expect(editor2.displayLayer.softWrapColumn).toBe( + editor2.getSoftWrapColumn() + ) }) it('ignores buffers with retired IDs', () => { const editor2 = TextEditor.deserialize(editor.serialize(), { assert: atom.assert, textEditors: atom.textEditors, - project: {bufferForIdSync () { return null }} + project: { + bufferForIdSync () { + return null + } + } }) expect(editor2).toBeNull() @@ -109,9 +139,9 @@ describe('TextEditor', () => { element.setWidth(100) jasmine.attachToDOM(element) - editor.update({showCursorOnSelection: false}) + editor.update({ showCursorOnSelection: false }) editor.setSelectedBufferRange([[1, 2], [3, 4]]) - editor.addSelectionForBufferRange([[5, 6], [7, 8]], {reversed: true}) + editor.addSelectionForBufferRange([[5, 6], [7, 8]], { reversed: true }) editor.setScrollTopRow(3) expect(editor.getScrollTopRow()).toBe(3) editor.setScrollLeftColumn(4) @@ -125,7 +155,9 @@ describe('TextEditor', () => { element2.setWidth(100) jasmine.attachToDOM(element2) expect(editor2.id).not.toBe(editor.id) - expect(editor2.getSelectedBufferRanges()).toEqual(editor.getSelectedBufferRanges()) + expect(editor2.getSelectedBufferRanges()).toEqual( + editor.getSelectedBufferRanges() + ) expect(editor2.getSelections()[1].isReversed()).toBeTruthy() expect(editor2.getScrollTopRow()).toBe(3) expect(editor2.getScrollLeftColumn()).toBe(4) @@ -136,9 +168,13 @@ describe('TextEditor', () => { // editor2 can now diverge from its origin edit session editor2.getLastSelection().setBufferRange([[2, 1], [4, 3]]) - expect(editor2.getSelectedBufferRanges()).not.toEqual(editor.getSelectedBufferRanges()) + expect(editor2.getSelectedBufferRanges()).not.toEqual( + editor.getSelectedBufferRanges() + ) editor2.unfoldBufferRow(4) - expect(editor2.isFoldedAtBufferRow(4)).not.toBe(editor.isFoldedAtBufferRow(4)) + expect(editor2.isFoldedAtBufferRow(4)).not.toBe( + editor.isFoldedAtBufferRow(4) + ) }) }) @@ -147,8 +183,8 @@ describe('TextEditor', () => { let changeSpy const { element } = editor // force element initialization element.setUpdatedSynchronously(false) - editor.update({showInvisibles: true}) - editor.onDidChange(changeSpy = jasmine.createSpy('onDidChange')) + editor.update({ showInvisibles: true }) + editor.onDidChange((changeSpy = jasmine.createSpy('onDidChange'))) const returnedPromise = editor.update({ tabLength: 6, @@ -194,8 +230,12 @@ describe('TextEditor', () => { }) it("returns ' — ' when opened files have identical file names", async () => { - const editor1 = await atom.workspace.open(path.join('sample-theme-1', 'readme')) - const editor2 = await atom.workspace.open(path.join('sample-theme-2', 'readme')) + const editor1 = await atom.workspace.open( + path.join('sample-theme-1', 'readme') + ) + const editor2 = await atom.workspace.open( + path.join('sample-theme-2', 'readme') + ) expect(editor1.getLongTitle()).toBe('readme \u2014 sample-theme-1') expect(editor2.getLongTitle()).toBe('readme \u2014 sample-theme-2') }) @@ -210,10 +250,16 @@ describe('TextEditor', () => { }) it("returns ' — ' when opened files have identical file and same parent dir name", async () => { - const editor1 = await atom.workspace.open(path.join('sample-theme-2', 'src', 'js', 'main.js')) - const editor2 = await atom.workspace.open(path.join('sample-theme-2', 'src', 'js', 'plugin', 'main.js')) + const editor1 = await atom.workspace.open( + path.join('sample-theme-2', 'src', 'js', 'main.js') + ) + const editor2 = await atom.workspace.open( + path.join('sample-theme-2', 'src', 'js', 'plugin', 'main.js') + ) expect(editor1.getLongTitle()).toBe('main.js \u2014 js') - expect(editor2.getLongTitle()).toBe(`main.js \u2014 ${path.join('js', 'plugin')}`) + expect(editor2.getLongTitle()).toBe( + `main.js \u2014 ${path.join('js', 'plugin')}` + ) }) it('returns the filename when the editor is not in the workspace', async () => { @@ -298,7 +344,9 @@ describe('TextEditor', () => { it('emits an event with the old position, new position, and the cursor that moved', () => { const cursorCallback = jasmine.createSpy('cursor-changed-position') - const editorCallback = jasmine.createSpy('editor-changed-cursor-position') + const editorCallback = jasmine.createSpy( + 'editor-changed-cursor-position' + ) editor.getLastCursor().onDidChangePosition(cursorCallback) editor.onDidChangeCursorPosition(editorCallback) @@ -321,7 +369,7 @@ describe('TextEditor', () => { describe('.setCursorScreenPosition(screenPosition)', () => { it('clears a goal column established by vertical movement', () => { // set a goal column by moving down - editor.setCursorScreenPosition({row: 3, column: lineLengths[3]}) + editor.setCursorScreenPosition({ row: 3, column: lineLengths[3] }) editor.moveDown() expect(editor.getCursorScreenPosition().column).not.toBe(6) @@ -367,7 +415,7 @@ describe('TextEditor', () => { it('retains the goal column across lines of differing length', () => { expect(lineLengths[6]).toBeGreaterThan(32) - editor.setCursorScreenPosition({row: 6, column: 32}) + editor.setCursorScreenPosition({ row: 6, column: 32 }) editor.moveUp() expect(editor.getCursorScreenPosition().column).toBe(lineLengths[5]) @@ -432,7 +480,7 @@ describe('TextEditor', () => { }) it('retains the goal column across lines of differing length', () => { - editor.setCursorScreenPosition({row: 3, column: lineLengths[3]}) + editor.setCursorScreenPosition({ row: 3, column: lineLengths[3] }) editor.moveDown() expect(editor.getCursorScreenPosition().column).toBe(lineLengths[4]) @@ -450,12 +498,20 @@ describe('TextEditor', () => { const lastLine = buffer.lineForRow(lastLineIndex) expect(lastLine.length).toBeGreaterThan(0) - editor.setCursorScreenPosition({row: lastLineIndex, column: editor.getTabLength()}) + editor.setCursorScreenPosition({ + row: lastLineIndex, + column: editor.getTabLength() + }) editor.moveDown() - expect(editor.getCursorScreenPosition()).toEqual({row: lastLineIndex, column: lastLine.length}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: lastLineIndex, + column: lastLine.length + }) editor.moveUp() - expect(editor.getCursorScreenPosition().column).toBe(editor.getTabLength()) + expect(editor.getCursorScreenPosition().column).toBe( + editor.getTabLength() + ) }) it('retains a goal column of 0 when moving back up', () => { @@ -463,7 +519,7 @@ describe('TextEditor', () => { const lastLine = buffer.lineForRow(lastLineIndex) expect(lastLine.length).toBeGreaterThan(0) - editor.setCursorScreenPosition({row: lastLineIndex, column: 0}) + editor.setCursorScreenPosition({ row: lastLineIndex, column: 0 }) editor.moveDown() editor.moveUp() expect(editor.getCursorScreenPosition().column).toBe(0) @@ -531,9 +587,12 @@ describe('TextEditor', () => { describe('when the cursor is in the first column', () => { describe('when there is a previous line', () => { it('wraps to the end of the previous line', () => { - editor.setCursorScreenPosition({row: 1, column: 0}) + editor.setCursorScreenPosition({ row: 1, column: 0 }) editor.moveLeft() - expect(editor.getCursorScreenPosition()).toEqual({row: 0, column: buffer.lineForRow(0).length}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 0, + column: buffer.lineForRow(0).length + }) }) it('moves the cursor by one row up and n columns to the left', () => { @@ -567,9 +626,12 @@ describe('TextEditor', () => { describe('when the cursor is on the first line', () => { it('remains in the same position (0,0)', () => { - editor.setCursorScreenPosition({row: 0, column: 0}) + editor.setCursorScreenPosition({ row: 0, column: 0 }) editor.moveLeft() - expect(editor.getCursorScreenPosition()).toEqual({row: 0, column: 0}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 0, + column: 0 + }) }) it('remains in the same position (0,0) when columnCount is specified', () => { @@ -667,7 +729,7 @@ describe('TextEditor', () => { const lastLine = buffer.lineForRow(lastLineIndex) expect(lastLine.length).toBeGreaterThan(0) - const lastPosition = {row: lastLineIndex, column: lastLine.length} + const lastPosition = { row: lastLineIndex, column: lastLine.length } editor.setCursorScreenPosition(lastPosition) editor.moveRight() @@ -840,7 +902,7 @@ describe('TextEditor', () => { describe('when invisible characters are enabled with soft tabs', () => { it('moves to the first character of the current line without being confused by the invisible characters', () => { - editor.update({showInvisibles: true}) + editor.update({ showInvisibles: true }) editor.setCursorScreenPosition([1, 7]) editor.moveToFirstCharacterOfLine() expect(editor.getCursorBufferPosition()).toEqual([1, 2]) @@ -851,8 +913,10 @@ describe('TextEditor', () => { describe('when invisible characters are enabled with hard tabs', () => { it('moves to the first character of the current line without being confused by the invisible characters', () => { - editor.update({showInvisibles: true}) - buffer.setTextInRange([[1, 0], [1, Infinity]], '\t\t\ta', {normalizeLineEndings: false}) + editor.update({ showInvisibles: true }) + buffer.setTextInRange([[1, 0], [1, Infinity]], '\t\t\ta', { + normalizeLineEndings: false + }) editor.setCursorScreenPosition([1, 7]) editor.moveToFirstCharacterOfLine() @@ -863,7 +927,7 @@ describe('TextEditor', () => { }) }) - it("clears the goal column", () => { + it('clears the goal column', () => { editor.setText('first\n\nthird') editor.setCursorScreenPosition([0, 3]) editor.moveDown() @@ -1332,7 +1396,9 @@ describe('TextEditor', () => { describe('.getCurrentParagraphBufferRange()', () => { it('returns the buffer range of the current paragraph, delimited by blank lines or the beginning / end of the file', () => { - buffer.setText(' ' + dedent` + buffer.setText( + ' ' + + dedent` I am the first paragraph, bordered by the beginning of the file @@ -1344,17 +1410,27 @@ describe('TextEditor', () => { I am the last paragraph, bordered by the end of the file.\ - `) + ` + ) // in a paragraph editor.setCursorBufferPosition([1, 7]) - expect(editor.getCurrentParagraphBufferRange()).toEqual([[0, 0], [2, 8]]) + expect(editor.getCurrentParagraphBufferRange()).toEqual([ + [0, 0], + [2, 8] + ]) editor.setCursorBufferPosition([7, 1]) - expect(editor.getCurrentParagraphBufferRange()).toEqual([[5, 0], [7, 3]]) + expect(editor.getCurrentParagraphBufferRange()).toEqual([ + [5, 0], + [7, 3] + ]) editor.setCursorBufferPosition([9, 10]) - expect(editor.getCurrentParagraphBufferRange()).toEqual([[9, 0], [10, 32]]) + expect(editor.getCurrentParagraphBufferRange()).toEqual([ + [9, 0], + [10, 32] + ]) // between paragraphs editor.setCursorBufferPosition([3, 1]) @@ -1415,7 +1491,9 @@ describe('TextEditor', () => { describe('getCursorAtScreenPosition(screenPosition)', () => { it('returns the cursor at the given screenPosition', () => { const cursor1 = editor.addCursorAtScreenPosition([0, 2]) - const cursor2 = editor.getCursorAtScreenPosition(cursor1.getScreenPosition()) + const cursor2 = editor.getCursorAtScreenPosition( + cursor1.getScreenPosition() + ) expect(cursor2).toBe(cursor1) }) }) @@ -1425,7 +1503,11 @@ describe('TextEditor', () => { editor.foldBufferRow(4) const cursor1 = editor.addCursorAtBufferPosition([8, 5]) const cursor2 = editor.addCursorAtBufferPosition([3, 5]) - expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [5, 5], [3, 5]]) + expect(editor.getCursorScreenPositions()).toEqual([ + [0, 0], + [5, 5], + [3, 5] + ]) }) }) @@ -1434,7 +1516,11 @@ describe('TextEditor', () => { const originalCursor = editor.getLastCursor() const cursor1 = editor.addCursorAtBufferPosition([8, 5]) const cursor2 = editor.addCursorAtBufferPosition([4, 5]) - expect(editor.getCursorsOrderedByBufferPosition()).toEqual([originalCursor, cursor2, cursor1]) + expect(editor.getCursorsOrderedByBufferPosition()).toEqual([ + originalCursor, + cursor2, + cursor1 + ]) }) }) @@ -1476,7 +1562,10 @@ describe('TextEditor', () => { describe('.getLastSelection()', () => { it('creates a new selection at (0, 0) if the last selection has been destroyed', () => { editor.getLastSelection().destroy() - expect(editor.getLastSelection().getBufferRange()).toEqual([[0, 0], [0, 0]]) + expect(editor.getLastSelection().getBufferRange()).toEqual([ + [0, 0], + [0, 0] + ]) }) it("doesn't get stuck in a infinite loop when called from ::onDidAddCursor after the last selection has been destroyed (regression)", () => { @@ -1486,7 +1575,10 @@ describe('TextEditor', () => { callCount++ editor.getLastSelection() }) - expect(editor.getLastSelection().getBufferRange()).toEqual([[0, 0], [0, 0]]) + expect(editor.getLastSelection().getBufferRange()).toEqual([ + [0, 0], + [0, 0] + ]) expect(callCount).toBe(1) }) }) @@ -1494,7 +1586,10 @@ describe('TextEditor', () => { describe('.getSelections()', () => { it('creates a new selection at (0, 0) if the last selection has been destroyed', () => { editor.getLastSelection().destroy() - expect(editor.getSelections()[0].getBufferRange()).toEqual([[0, 0], [0, 0]]) + expect(editor.getSelections()[0].getBufferRange()).toEqual([ + [0, 0], + [0, 0] + ]) }) }) @@ -1503,7 +1598,9 @@ describe('TextEditor', () => { let rangeChangedHandler editor.setSelectedBufferRange([[3, 0], [4, 5]]) - editor.onDidChangeSelectionRange(rangeChangedHandler = jasmine.createSpy()) + editor.onDidChangeSelectionRange( + (rangeChangedHandler = jasmine.createSpy()) + ) editor.selectToBufferPosition([6, 2]) expect(rangeChangedHandler).toHaveBeenCalled() @@ -1541,7 +1638,11 @@ describe('TextEditor', () => { }) it('merges selections when they intersect when moving down', () => { - editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[1, 10], [1, 20]], [[2, 15], [3, 25]]]) + editor.setSelectedBufferRanges([ + [[0, 9], [0, 13]], + [[1, 10], [1, 20]], + [[2, 15], [3, 25]] + ]) const [selection1, selection2, selection3] = editor.getSelections() editor.selectDown() @@ -1551,7 +1652,10 @@ describe('TextEditor', () => { }) it('merges selections when they intersect when moving up', () => { - editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[1, 10], [1, 20]]], {reversed: true}) + editor.setSelectedBufferRanges( + [[[0, 9], [0, 13]], [[1, 10], [1, 20]]], + { reversed: true } + ) const [selection1, selection2] = editor.getSelections() editor.selectUp() @@ -1562,7 +1666,10 @@ describe('TextEditor', () => { }) it('merges selections when they intersect when moving left', () => { - editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[0, 13], [1, 20]]], {reversed: true}) + editor.setSelectedBufferRanges( + [[[0, 9], [0, 13]], [[0, 13], [1, 20]]], + { reversed: true } + ) const [selection1, selection2] = editor.getSelections() editor.selectLeft() @@ -1583,7 +1690,10 @@ describe('TextEditor', () => { describe('when counts are passed into the selection functions', () => { it("expands each selection to its cursor's new location", () => { - editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[3, 16], [3, 21]]]) + editor.setSelectedBufferRanges([ + [[0, 9], [0, 13]], + [[3, 16], [3, 21]] + ]) const [selection1, selection2] = editor.getSelections() editor.selectRight(2) @@ -1687,8 +1797,8 @@ describe('TextEditor', () => { editor.selectToScreenPosition([4, 11]) selections = editor.getSelections() - expect(selections.length).toBe(1); - [selection1] = selections + expect(selections.length).toBe(1) + ;[selection1] = selections expect(selection1.getScreenRange()).toEqual([[3, 10], [7, 4]]) expect(selection1.isReversed()).toBeTruthy() }) @@ -1701,7 +1811,10 @@ describe('TextEditor', () => { editor.selectToTop() expect(editor.getCursors().length).toBe(1) expect(editor.getCursorBufferPosition()).toEqual([0, 0]) - expect(editor.getLastSelection().getBufferRange()).toEqual([[0, 0], [11, 2]]) + expect(editor.getLastSelection().getBufferRange()).toEqual([ + [0, 0], + [11, 2] + ]) expect(editor.getLastSelection().isReversed()).toBeTruthy() }) }) @@ -1713,7 +1826,10 @@ describe('TextEditor', () => { editor.selectToBottom() expect(editor.getCursors().length).toBe(1) expect(editor.getCursorBufferPosition()).toEqual([12, 2]) - expect(editor.getLastSelection().getBufferRange()).toEqual([[9, 3], [12, 2]]) + expect(editor.getLastSelection().getBufferRange()).toEqual([ + [9, 3], + [12, 2] + ]) expect(editor.getLastSelection().isReversed()).toBeFalsy() }) }) @@ -1721,7 +1837,9 @@ describe('TextEditor', () => { describe('.selectAll()', () => { it('selects the entire buffer', () => { editor.selectAll() - expect(editor.getLastSelection().getBufferRange()).toEqual(buffer.getRange()) + expect(editor.getLastSelection().getBufferRange()).toEqual( + buffer.getRange() + ) }) }) @@ -1772,7 +1890,9 @@ describe('TextEditor', () => { editor.setCursorScreenPosition([1, 2]) editor.selectLinesContainingCursors() expect(editor.getSelectedBufferRange()).toEqual([[1, 0], [2, 0]]) - expect(editor.getSelectedText()).toBe(' var sort = function(items) {\n') + expect(editor.getSelectedText()).toBe( + ' var sort = function(items) {\n' + ) editor.setCursorScreenPosition([12, 2]) editor.selectLinesContainingCursors() @@ -1867,7 +1987,12 @@ describe('TextEditor', () => { editor.selectToPreviousWordBoundary() expect(editor.getSelections().length).toBe(4) - const [selection1, selection2, selection3, selection4] = editor.getSelections() + const [ + selection1, + selection2, + selection3, + selection4 + ] = editor.getSelections() expect(selection1.getBufferRange()).toEqual([[0, 8], [0, 4]]) expect(selection1.isReversed()).toBeTruthy() expect(selection2.getBufferRange()).toEqual([[2, 0], [1, 30]]) @@ -1889,7 +2014,12 @@ describe('TextEditor', () => { editor.selectToNextWordBoundary() expect(editor.getSelections().length).toBe(4) - const [selection1, selection2, selection3, selection4] = editor.getSelections() + const [ + selection1, + selection2, + selection3, + selection4 + ] = editor.getSelections() expect(selection1.getBufferRange()).toEqual([[0, 8], [0, 13]]) expect(selection1.isReversed()).toBeFalsy() expect(selection2.getBufferRange()).toEqual([[2, 40], [3, 0]]) @@ -1912,7 +2042,12 @@ describe('TextEditor', () => { editor.addCursorAtBufferPosition([1, 7]) editor.addCursorAtBufferPosition([2, 5]) editor.addCursorAtBufferPosition([3, 3]) - const [selection1, selection2, selection3, selection4] = editor.getSelections() + const [ + selection1, + selection2, + selection3, + selection4 + ] = editor.getSelections() editor.selectToPreviousSubwordBoundary() expect(selection1.getBufferRange()).toEqual([[0, 1], [0, 5]]) @@ -1937,7 +2072,12 @@ describe('TextEditor', () => { editor.addCursorAtBufferPosition([1, 7]) editor.addCursorAtBufferPosition([2, 2]) editor.addCursorAtBufferPosition([3, 1]) - const [selection1, selection2, selection3, selection4] = editor.getSelections() + const [ + selection1, + selection2, + selection3, + selection4 + ] = editor.getSelections() editor.selectToNextSubwordBoundary() expect(selection1.getBufferRange()).toEqual([[0, 1], [0, 4]]) @@ -2083,13 +2223,23 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([0, 1]) editor.addCursorAtBufferPosition([0, 12]) - const scopeDescriptors = editor.getCursors().map(c => c.getScopeDescriptor()) + const scopeDescriptors = editor + .getCursors() + .map(c => c.getScopeDescriptor()) expect(scopeDescriptors[0].getScopesArray()).toEqual(['source.js']) - expect(scopeDescriptors[1].getScopesArray()).toEqual(['source.js', 'string.quoted']) + expect(scopeDescriptors[1].getScopesArray()).toEqual([ + 'source.js', + 'string.quoted' + ]) - spyOn(editor.getBuffer().getLanguageMode(), 'getNonWordCharacters').andCallFake(function (position) { - const result = '/\()"\':,.;<>~!@#$%^&*|+=[]{}`?' - const scopes = this.scopeDescriptorForPosition(position).getScopesArray() + spyOn( + editor.getBuffer().getLanguageMode(), + 'getNonWordCharacters' + ).andCallFake(function (position) { + const result = '/()"\':,.;<>~!@#$%^&*|+=[]{}`?' + const scopes = this.scopeDescriptorForPosition( + position + ).getScopesArray() if (scopes.some(scope => scope.startsWith('string'))) { return result } else { @@ -2122,8 +2272,8 @@ describe('TextEditor', () => { expect(selection2.getBufferRange()).toEqual([[1, 2], [1, 7]]) expect(selection2.isReversed()).toBeTruthy() - editor.selectToFirstCharacterOfLine(); - [selection1, selection2] = editor.getSelections() + editor.selectToFirstCharacterOfLine() + ;[selection1, selection2] = editor.getSelections() expect(selection1.getBufferRange()).toEqual([[0, 0], [0, 5]]) expect(selection1.isReversed()).toBeTruthy() expect(selection2.getBufferRange()).toEqual([[1, 0], [1, 7]]) @@ -2134,7 +2284,10 @@ describe('TextEditor', () => { describe('.setSelectedBufferRanges(ranges)', () => { it('clears existing selections and creates selections for each of the given ranges', () => { editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[4, 4], [5, 5]]]) - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 2], [3, 3]], [[4, 4], [5, 5]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 2], [3, 3]], + [[4, 4], [5, 5]] + ]) editor.setSelectedBufferRanges([[[5, 5], [6, 6]]]) expect(editor.getSelectedBufferRanges()).toEqual([[[5, 5], [6, 6]]]) @@ -2147,7 +2300,10 @@ describe('TextEditor', () => { it('does not merge non-empty adjacent selections', () => { editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[3, 3], [5, 5]]]) - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 2], [3, 3]], [[3, 3], [5, 5]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 2], [3, 3]], + [[3, 3], [5, 5]] + ]) }) it('recycles existing selection instances', () => { @@ -2183,7 +2339,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[0, 0], [0, 0]]) editor.foldBufferRowRange(1, 4) editor.foldBufferRowRange(6, 8) - editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[6, 0], [6, 1]]], {preserveFolds: true}) + editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[6, 0], [6, 1]]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(1)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() }) @@ -2195,7 +2353,10 @@ describe('TextEditor', () => { it('clears existing selections and creates selections for each of the given ranges', () => { editor.setSelectedScreenRanges([[[3, 4], [3, 7]], [[5, 4], [5, 7]]]) - expect(editor.getSelectedBufferRanges()).toEqual([[[3, 4], [3, 7]], [[8, 4], [8, 7]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[3, 4], [3, 7]], + [[8, 4], [8, 7]] + ]) editor.setSelectedScreenRanges([[[6, 2], [6, 4]]]) expect(editor.getSelectedScreenRanges()).toEqual([[[6, 2], [6, 4]]]) @@ -2241,7 +2402,10 @@ describe('TextEditor', () => { describe('.addSelectionForBufferRange(bufferRange)', () => { it('adds a selection for the specified buffer range', () => { editor.addSelectionForBufferRange([[3, 4], [5, 6]]) - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 0]], [[3, 4], [5, 6]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 0], [0, 0]], + [[3, 4], [5, 6]] + ]) }) }) @@ -2316,7 +2480,10 @@ describe('TextEditor', () => { }) it('takes atomic tokens into account', async () => { - editor = await atom.workspace.open('sample-with-tabs-and-leading-comment.coffee', {autoIndent: false}) + editor = await atom.workspace.open( + 'sample-with-tabs-and-leading-comment.coffee', + { autoIndent: false } + ) editor.setSelectedBufferRange([[2, 1], [2, 3]]) editor.addSelectionBelow() expect(editor.getSelectedBufferRanges()).toEqual([ @@ -2392,7 +2559,9 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([0, 1]) let addedSelectionCount = 0 - editor.onDidAddSelection(() => { addedSelectionCount++ }) + editor.onDidAddSelection(() => { + addedSelectionCount++ + }) editor.addSelectionBelow() editor.addSelectionBelow() @@ -2451,7 +2620,10 @@ describe('TextEditor', () => { }) it('takes atomic tokens into account', async () => { - editor = await atom.workspace.open('sample-with-tabs-and-leading-comment.coffee', {autoIndent: false}) + editor = await atom.workspace.open( + 'sample-with-tabs-and-leading-comment.coffee', + { autoIndent: false } + ) editor.setSelectedBufferRange([[3, 1], [3, 2]]) editor.addSelectionAbove() expect(editor.getSelectedBufferRanges()).toEqual([ @@ -2527,7 +2699,9 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([4, 1]) let addedSelectionCount = 0 - editor.onDidAddSelection(() => { addedSelectionCount++ }) + editor.onDidAddSelection(() => { + addedSelectionCount++ + }) editor.addSelectionAbove() editor.addSelectionAbove() @@ -2565,7 +2739,12 @@ describe('TextEditor', () => { const selection2 = editor.addSelectionForBufferRange([[3, 25], [3, 34]]) const selection3 = editor.addSelectionForBufferRange([[8, 4], [8, 10]]) const selection4 = editor.addSelectionForBufferRange([[1, 6], [1, 10]]) - expect(editor.getSelections()).toEqual([selection, selection2, selection3, selection4]) + expect(editor.getSelections()).toEqual([ + selection, + selection2, + selection3, + selection4 + ]) return [selection, selection2, selection3, selection4] } @@ -2582,7 +2761,10 @@ describe('TextEditor', () => { expect(editor.getSelections()).toEqual([selection1]) expect(autoscrollEvents).toEqual([ - {screenRange: selection1.getScreenRange(), options: {center: true, reversed: false}} + { + screenRange: selection1.getScreenRange(), + options: { center: true, reversed: false } + } ]) }) }) @@ -2620,7 +2802,9 @@ describe('TextEditor', () => { expect(editor2.getText()).toBe(editor.getText()) editor.setSelectedBufferRanges([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) editor2.setSelectedBufferRanges([[[8, 7], [6, 5]], [[4, 3], [2, 1]]]) - expect(editor2.getSelectedBufferRanges()).not.toEqual(editor.getSelectedBufferRanges()) + expect(editor2.getSelectedBufferRanges()).not.toEqual( + editor.getSelectedBufferRanges() + ) }) }) @@ -2629,13 +2813,15 @@ describe('TextEditor', () => { it('moves the line under the cursor up', () => { editor.setCursorBufferPosition([1, 0]) editor.moveLineUp() - expect(editor.getTextInBufferRange([[0, 0], [0, 30]])).toBe(' var sort = function(items) {') + expect(editor.getTextInBufferRange([[0, 0], [0, 30]])).toBe( + ' var sort = function(items) {' + ) expect(editor.indentationForBufferRow(0)).toBe(1) expect(editor.indentationForBufferRow(1)).toBe(0) }) it("updates the line's indentation when the the autoIndent setting is true", () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setCursorBufferPosition([1, 0]) editor.moveLineUp() expect(editor.indentationForBufferRow(0)).toBe(0) @@ -2646,24 +2832,35 @@ describe('TextEditor', () => { describe('when the selection spans a single line', () => { describe('when there is no fold in the preceeding row', () => it('moves the line to the preceding row', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) editor.setSelectedBufferRange([[3, 2], [3, 9]]) editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[2, 2], [2, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - }) - ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + })) describe('when the cursor is at the beginning of a fold', () => it('moves the line to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[4, 2], [4, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[4, 2], [4, 9]], { + preserveFolds: true + }) expect(editor.getSelectedBufferRange()).toEqual([[4, 2], [4, 9]]) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -2675,20 +2872,25 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [3, 9]]) - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() - }) - ) + })) describe('when the preceding row consists of folded code', () => it('moves the line above the folded row and perseveres the correct folds', () => { - expect(editor.lineTextForBufferRow(8)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(8)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.lineTextForBufferRow(9)).toBe(' };') editor.foldBufferRowRange(4, 7) @@ -2703,38 +2905,57 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[4, 0], [4, 4]]) - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() - }) - ) + })) }) describe('when the selection spans multiple lines', () => { it('moves the lines spanned by the selection to the preceding row', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.setSelectedBufferRange([[3, 2], [4, 9]]) editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[2, 2], [3, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(4)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' if (items.length <= 1) return items;' + ) }) describe("when the selection's end intersects a fold", () => it('moves the lines to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[3, 2], [4, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[3, 2], [4, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(3)).toBeFalsy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -2746,9 +2967,15 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[2, 2], [3, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(7)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() @@ -2756,15 +2983,18 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() - }) - ) + })) describe("when the selection's start intersects a fold", () => it('moves the lines to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[4, 2], [8, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[4, 2], [8, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -2776,9 +3006,15 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [7, 9]]) - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(7)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(8)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(8)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -2786,29 +3022,42 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - }) - ) + })) }) describe('when the selection spans multiple lines, but ends at column 0', () => { it('does not move the last line of the selection', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.setSelectedBufferRange([[3, 2], [4, 0]]) editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[2, 2], [3, 0]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) }) }) describe('when the preceeding row is a folded row', () => { it('moves the lines spanned by the selection to the preceeding row, but preserves the folded code', () => { - expect(editor.lineTextForBufferRow(8)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(8)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.lineTextForBufferRow(9)).toBe(' };') editor.foldBufferRowRange(4, 7) @@ -2822,9 +3071,13 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[4, 0], [5, 2]]) - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.lineTextForBufferRow(5)).toBe(' };') - expect(editor.lineTextForBufferRow(6)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(6)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(5)).toBeFalsy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() @@ -2839,28 +3092,49 @@ describe('TextEditor', () => { describe('when all the selections span different lines', () => { describe('when there is no folds', () => it('moves all lines that are spanned by a selection to the preceding row', () => { - editor.setSelectedBufferRanges([[[1, 2], [1, 9]], [[3, 2], [3, 9]], [[5, 2], [5, 9]]]) + editor.setSelectedBufferRanges([ + [[1, 2], [1, 9]], + [[3, 2], [3, 9]], + [[5, 2], [5, 9]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 2], [0, 9]], [[2, 2], [2, 9]], [[4, 2], [4, 9]]]) - expect(editor.lineTextForBufferRow(0)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(1)).toBe('var quicksort = function () {') - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' current = items.shift();') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') - }) - ) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 2], [0, 9]], + [[2, 2], [2, 9]], + [[4, 2], [4, 9]] + ]) + expect(editor.lineTextForBufferRow(0)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + 'var quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' current = items.shift();' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) + })) describe('when one selection intersects a fold', () => it('moves the lines to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRanges([ - [[2, 2], [2, 9]], - [[4, 2], [4, 9]] - ], {preserveFolds: true}) + editor.setSelectedBufferRanges( + [[[2, 2], [2, 9]], [[4, 2], [4, 9]]], + { preserveFolds: true } + ) expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() expect(editor.isFoldedAtBufferRow(3)).toBeFalsy() @@ -2878,10 +3152,18 @@ describe('TextEditor', () => { [[3, 2], [3, 9]] ]) - expect(editor.lineTextForBufferRow(1)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(2)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(1)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.isFoldedAtBufferRow(1)).toBeFalsy() expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() @@ -2891,8 +3173,7 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - }) - ) + })) describe('when there is a fold', () => it('moves all lines that spanned by a selection to preceding row, preserving all folds', () => { @@ -2904,24 +3185,35 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - editor.setSelectedBufferRanges([[[8, 0], [8, 3]], [[11, 0], [11, 5]]]) + editor.setSelectedBufferRanges([ + [[8, 0], [8, 3]], + [[11, 0], [11, 5]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[4, 0], [4, 3]], [[10, 0], [10, 5]]]) - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(10)).toBe(' return sort(Array.apply(this, arguments));') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[4, 0], [4, 3]], + [[10, 0], [10, 5]] + ]) + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(10)).toBe( + ' return sort(Array.apply(this, arguments));' + ) expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() - }) - ) + })) }) describe('when there are many folds', () => { beforeEach(async () => { - editor = await atom.workspace.open('sample-with-many-folds.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-many-folds.js', { + autoIndent: false + }) }) describe('and many selections intersects folded rows', () => @@ -2929,10 +3221,10 @@ describe('TextEditor', () => { editor.foldBufferRowRange(2, 4) editor.foldBufferRowRange(7, 9) - editor.setSelectedBufferRanges([ - [[1, 0], [5, 4]], - [[7, 0], [7, 4]] - ], {preserveFolds: true}) + editor.setSelectedBufferRanges( + [[[1, 0], [5, 4]], [[7, 0], [7, 4]]], + { preserveFolds: true } + ) editor.moveLineUp() @@ -2951,27 +3243,42 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() - }) - ) + })) }) describe('when some of the selections span the same lines', () => { it('moves lines that contain multiple selections correctly', () => { - editor.setSelectedBufferRanges([[[3, 2], [3, 9]], [[3, 12], [3, 13]]]) + editor.setSelectedBufferRanges([ + [[3, 2], [3, 9]], + [[3, 12], [3, 13]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 2], [2, 9]], [[2, 12], [2, 13]]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 2], [2, 9]], + [[2, 12], [2, 13]] + ]) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) }) }) describe('when one of the selections spans line 0', () => { it("doesn't move any lines, since line 0 can't move", () => { - editor.setSelectedBufferRanges([[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[4, 2], [4, 9]]]) + editor.setSelectedBufferRanges([ + [[0, 2], [1, 9]], + [[2, 2], [2, 9]], + [[4, 2], [4, 9]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[4, 2], [4, 9]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 2], [1, 9]], + [[2, 2], [2, 9]], + [[4, 2], [4, 9]] + ]) expect(buffer.isModified()).toBe(false) }) }) @@ -2979,11 +3286,19 @@ describe('TextEditor', () => { describe('when one of the selections spans the last line, and it is empty', () => { it("doesn't move any lines, since the last line can't move", () => { buffer.append('\n') - editor.setSelectedBufferRanges([[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[13, 0], [13, 0]]]) + editor.setSelectedBufferRanges([ + [[0, 2], [1, 9]], + [[2, 2], [2, 9]], + [[13, 0], [13, 0]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[13, 0], [13, 0]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 2], [1, 9]], + [[2, 2], [2, 9]], + [[13, 0], [13, 0]] + ]) }) }) }) @@ -2993,13 +3308,15 @@ describe('TextEditor', () => { it('moves the line under the cursor down', () => { editor.setCursorBufferPosition([0, 0]) editor.moveLineDown() - expect(editor.getTextInBufferRange([[1, 0], [1, 31]])).toBe('var quicksort = function () {') + expect(editor.getTextInBufferRange([[1, 0], [1, 31]])).toBe( + 'var quicksort = function () {' + ) expect(editor.indentationForBufferRow(0)).toBe(1) expect(editor.indentationForBufferRow(1)).toBe(0) }) it("updates the line's indentation when the editor.autoIndent setting is true", () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setCursorBufferPosition([0, 0]) editor.moveLineDown() expect(editor.indentationForBufferRow(0)).toBe(1) @@ -3010,24 +3327,35 @@ describe('TextEditor', () => { describe('when the selection spans a single line', () => { describe('when there is no fold in the following row', () => it('moves the line to the following row', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) editor.setSelectedBufferRange([[2, 2], [2, 9]]) editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [3, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - }) - ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + })) describe('when the cursor is at the beginning of a fold', () => it('moves the line to the following row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[4, 2], [4, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[4, 2], [4, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -3038,21 +3366,28 @@ describe('TextEditor', () => { editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[5, 2], [5, 9]]) - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() - }) - ) + })) describe('when the following row is a folded row', () => it('moves the line below the folded row and preserves the fold', () => { - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) @@ -3066,56 +3401,87 @@ describe('TextEditor', () => { editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[7, 0], [7, 4]]) - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - }) - ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + })) }) describe('when the selection spans multiple lines', () => { it('moves the lines spanned by the selection to the following row', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.setSelectedBufferRange([[2, 2], [3, 9]]) editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [4, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) }) }) describe('when the selection spans multiple lines, but ends at column 0', () => { it('does not move the last line of the selection', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.setSelectedBufferRange([[2, 2], [3, 0]]) editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [4, 0]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) }) }) describe("when the selection's end intersects a fold", () => { it('moves the lines to the following row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[3, 2], [4, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[3, 2], [4, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(3)).toBeFalsy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -3127,9 +3493,15 @@ describe('TextEditor', () => { editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[4, 2], [5, 9]]) - expect(editor.lineTextForBufferRow(3)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(4)).toBeFalsy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -3142,10 +3514,14 @@ describe('TextEditor', () => { describe("when the selection's start intersects a fold", () => { it('moves the lines to the following row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[4, 2], [8, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[4, 2], [8, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -3158,8 +3534,12 @@ describe('TextEditor', () => { expect(editor.getSelectedBufferRange()).toEqual([[5, 2], [9, 9]]) expect(editor.lineTextForBufferRow(4)).toBe(' };') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(9)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(9)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.isFoldedAtBufferRow(4)).toBeFalsy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -3173,8 +3553,12 @@ describe('TextEditor', () => { describe('when the following row is a folded row', () => { it('moves the lines spanned by the selection to the following row, but preserves the folded code', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) editor.foldBufferRowRange(4, 7) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -3187,14 +3571,18 @@ describe('TextEditor', () => { editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[6, 0], [7, 2]]) - expect(editor.lineTextForBufferRow(2)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(1)).toBeFalsy() expect(editor.isFoldedAtBufferRow(2)).toBeTruthy() expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeFalsy() - expect(editor.lineTextForBufferRow(6)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(6)).toBe( + ' if (items.length <= 1) return items;' + ) }) }) @@ -3202,7 +3590,9 @@ describe('TextEditor', () => { it('appends line ending to last line and moves the lines spanned by the selection to the preceeding row', () => { expect(editor.lineTextForBufferRow(9)).toBe(' };') expect(editor.lineTextForBufferRow(10)).toBe('') - expect(editor.lineTextForBufferRow(11)).toBe(' return sort(Array.apply(this, arguments));') + expect(editor.lineTextForBufferRow(11)).toBe( + ' return sort(Array.apply(this, arguments));' + ) expect(editor.lineTextForBufferRow(12)).toBe('};') editor.setSelectedBufferRange([[10, 0], [12, 2]]) @@ -3210,7 +3600,9 @@ describe('TextEditor', () => { expect(editor.getSelectedBufferRange()).toEqual([[9, 0], [11, 2]]) expect(editor.lineTextForBufferRow(9)).toBe('') - expect(editor.lineTextForBufferRow(10)).toBe(' return sort(Array.apply(this, arguments));') + expect(editor.lineTextForBufferRow(10)).toBe( + ' return sort(Array.apply(this, arguments));' + ) expect(editor.lineTextForBufferRow(11)).toBe('};') expect(editor.lineTextForBufferRow(12)).toBe(' };') }) @@ -3221,22 +3613,43 @@ describe('TextEditor', () => { describe('when all the selections span different lines', () => { describe('when there is no folds', () => it('moves all lines that are spanned by a selection to the following row', () => { - editor.setSelectedBufferRanges([[[1, 2], [1, 9]], [[3, 2], [3, 9]], [[5, 2], [5, 9]]]) + editor.setSelectedBufferRanges([ + [[1, 2], [1, 9]], + [[3, 2], [3, 9]], + [[5, 2], [5, 9]] + ]) editor.moveLineDown() - expect(editor.getSelectedBufferRanges()).toEqual([[[6, 2], [6, 9]], [[4, 2], [4, 9]], [[2, 2], [2, 9]]]) - expect(editor.lineTextForBufferRow(1)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(2)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(5)).toBe(' current < pivot ? left.push(current) : right.push(current);') - expect(editor.lineTextForBufferRow(6)).toBe(' current = items.shift();') - }) - ) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[6, 2], [6, 9]], + [[4, 2], [4, 9]], + [[2, 2], [2, 9]] + ]) + expect(editor.lineTextForBufferRow(1)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' current = items.shift();' + ) + })) describe('when there are many folds', () => { beforeEach(async () => { - editor = await atom.workspace.open('sample-with-many-folds.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-many-folds.js', { + autoIndent: false + }) }) describe('and many selections intersects folded rows', () => @@ -3244,18 +3657,22 @@ describe('TextEditor', () => { editor.foldBufferRowRange(2, 4) editor.foldBufferRowRange(7, 9) - editor.setSelectedBufferRanges([ - [[2, 0], [2, 4]], - [[6, 0], [10, 4]] - ], {preserveFolds: true}) + editor.setSelectedBufferRanges( + [[[2, 0], [2, 4]], [[6, 0], [10, 4]]], + { preserveFolds: true } + ) editor.moveLineDown() expect(editor.lineTextForBufferRow(2)).toEqual('6;') - expect(editor.lineTextForBufferRow(3)).toEqual('function f3() {') + expect(editor.lineTextForBufferRow(3)).toEqual( + 'function f3() {' + ) expect(editor.lineTextForBufferRow(6)).toEqual('12;') expect(editor.lineTextForBufferRow(7)).toEqual('7;') - expect(editor.lineTextForBufferRow(8)).toEqual('function f8() {') + expect(editor.lineTextForBufferRow(8)).toEqual( + 'function f8() {' + ) expect(editor.lineTextForBufferRow(11)).toEqual('11;') expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() @@ -3268,8 +3685,7 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(9)).toBeTruthy() expect(editor.isFoldedAtBufferRow(10)).toBeTruthy() expect(editor.isFoldedAtBufferRow(11)).toBeFalsy() - }) - ) + })) }) describe('when there is a fold below one of the selected row', () => @@ -3282,20 +3698,33 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - editor.setSelectedBufferRanges([[[1, 2], [1, 6]], [[3, 0], [3, 4]], [[8, 0], [8, 3]]]) + editor.setSelectedBufferRanges([ + [[1, 2], [1, 6]], + [[3, 0], [3, 4]], + [[8, 0], [8, 3]] + ]) editor.moveLineDown() - expect(editor.getSelectedBufferRanges()).toEqual([[[9, 0], [9, 3]], [[7, 0], [7, 4]], [[2, 2], [2, 6]]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var sort = function(items) {') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[9, 0], [9, 3]], + [[7, 0], [7, 4]], + [[2, 2], [2, 6]] + ]) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var sort = function(items) {' + ) expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(9)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - }) - ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(9)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + })) describe('when there is a fold below a group of multiple selections without any lines with no selection in-between', () => it('moves all the lines below the fold, preserving the fold', () => { @@ -3307,31 +3736,44 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - editor.setSelectedBufferRanges([[[2, 2], [2, 6]], [[3, 0], [3, 4]]]) + editor.setSelectedBufferRanges([ + [[2, 2], [2, 6]], + [[3, 0], [3, 4]] + ]) editor.moveLineDown() - expect(editor.getSelectedBufferRanges()).toEqual([[[7, 0], [7, 4]], [[6, 2], [6, 6]]]) - expect(editor.lineTextForBufferRow(2)).toBe(' while(items.length > 0) {') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[7, 0], [7, 4]], + [[6, 2], [6, 6]] + ]) + expect(editor.lineTextForBufferRow(2)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(2)).toBeTruthy() expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeFalsy() - expect(editor.lineTextForBufferRow(6)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - }) - ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + })) }) describe('when one selection intersects a fold', () => { it('moves the lines to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRanges([ - [[2, 2], [2, 9]], - [[4, 2], [4, 9]] - ], {preserveFolds: true}) + editor.setSelectedBufferRanges( + [[[2, 2], [2, 9]], [[4, 2], [4, 9]]], + { preserveFolds: true } + ) expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() expect(editor.isFoldedAtBufferRow(3)).toBeFalsy() @@ -3349,11 +3791,19 @@ describe('TextEditor', () => { [[3, 2], [3, 9]] ]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) expect(editor.lineTextForBufferRow(9)).toBe(' };') expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() @@ -3369,11 +3819,19 @@ describe('TextEditor', () => { describe('when some of the selections span the same lines', () => { it('moves lines that contain multiple selections correctly', () => { - editor.setSelectedBufferRanges([[[3, 2], [3, 9]], [[3, 12], [3, 13]]]) + editor.setSelectedBufferRanges([ + [[3, 2], [3, 9]], + [[3, 12], [3, 13]] + ]) editor.moveLineDown() - expect(editor.getSelectedBufferRanges()).toEqual([[[4, 12], [4, 13]], [[4, 2], [4, 9]]]) - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[4, 12], [4, 13]], + [[4, 2], [4, 9]] + ]) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) }) }) @@ -3381,7 +3839,7 @@ describe('TextEditor', () => { beforeEach(() => { editor.setSoftWrapped(true) editor.setEditorWidthInChars(80) - editor.setText(dedent ` + editor.setText(dedent` 1 2 Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. @@ -3418,7 +3876,7 @@ describe('TextEditor', () => { it('replaces the selection with the given text', () => { const range = editor.insertText('xxx') - expect(range).toEqual([ [[1, 0], [1, 3]] ]) + expect(range).toEqual([[[1, 0], [1, 3]]]) expect(buffer.lineForRow(1)).toBe('xxxvar sort = function(items) {') }) }) @@ -3431,7 +3889,9 @@ describe('TextEditor', () => { editor.insertText('xxx') - expect(buffer.lineForRow(1)).toBe(' xxxvarxxx sort = function(items) {') + expect(buffer.lineForRow(1)).toBe( + ' xxxvarxxx sort = function(items) {' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([1, 5]) @@ -3446,8 +3906,12 @@ describe('TextEditor', () => { editor.insertText('xxx') - expect(buffer.lineForRow(1)).toBe(' xxxvar sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' xxxif (items.length <= 1) return items;') + expect(buffer.lineForRow(1)).toBe( + ' xxxvar sort = function(items) {' + ) + expect(buffer.lineForRow(2)).toBe( + ' xxxif (items.length <= 1) return items;' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([1, 5]) @@ -3459,7 +3923,10 @@ describe('TextEditor', () => { describe('when there are multiple non-empty selections', () => { describe('when the selections are on the same line', () => { it('replaces each selection range with the inserted characters', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[0, 22], [0, 24]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[0, 22], [0, 24]] + ]) editor.insertText('x') const [cursor1, cursor2] = editor.getCursors() @@ -3481,7 +3948,9 @@ describe('TextEditor', () => { editor.insertText('xxx') expect(buffer.lineForRow(1)).toBe('xxxvar sort = function(items) {') - expect(buffer.lineForRow(2)).toBe('xxxif (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'xxxif (items.length <= 1) return items;' + ) const [selection1, selection2] = editor.getSelections() expect(selection1.isEmpty()).toBeTruthy() @@ -3505,9 +3974,21 @@ describe('TextEditor', () => { beforeEach(() => editor.setSelectedBufferRange([[1, 0], [1, 2]])) it('notifies the observers when inserting text', () => { - const willInsertSpy = jasmine.createSpy().andCallFake(() => expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {')) + const willInsertSpy = jasmine + .createSpy() + .andCallFake(() => + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) {' + ) + ) - const didInsertSpy = jasmine.createSpy().andCallFake(() => expect(buffer.lineForRow(1)).toBe('xxxvar sort = function(items) {')) + const didInsertSpy = jasmine + .createSpy() + .andCallFake(() => + expect(buffer.lineForRow(1)).toBe( + 'xxxvar sort = function(items) {' + ) + ) editor.onWillInsertText(willInsertSpy) editor.onDidInsertText(didInsertSpy) @@ -3527,7 +4008,9 @@ describe('TextEditor', () => { }) it('cancels text insertion when an ::onWillInsertText observer calls cancel on an event', () => { - const willInsertSpy = jasmine.createSpy().andCallFake(({cancel}) => cancel()) + const willInsertSpy = jasmine + .createSpy() + .andCallFake(({ cancel }) => cancel()) const didInsertSpy = jasmine.createSpy() @@ -3544,12 +4027,9 @@ describe('TextEditor', () => { describe("when the undo option is set to 'skip'", () => { it('groups the change with the previous change for purposes of undo and redo', () => { - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[1, 0], [1, 0]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[1, 0], [1, 0]]]) editor.insertText('x') - editor.insertText('y', {undo: 'skip'}) + editor.insertText('y', { undo: 'skip' }) editor.undo() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') @@ -3561,18 +4041,21 @@ describe('TextEditor', () => { describe('when there is a single cursor', () => { describe('when the cursor is at the beginning of a line', () => { it('inserts an empty line before it', () => { - editor.setCursorScreenPosition({row: 1, column: 0}) + editor.setCursorScreenPosition({ row: 1, column: 0 }) editor.insertNewline() expect(buffer.lineForRow(1)).toBe('') - expect(editor.getCursorScreenPosition()).toEqual({row: 2, column: 0}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 2, + column: 0 + }) }) }) describe('when the cursor is in the middle of a line', () => { it('splits the current line to form a new line', () => { - editor.setCursorScreenPosition({row: 1, column: 6}) + editor.setCursorScreenPosition({ row: 1, column: 6 }) const originalLine = buffer.lineForRow(1) const lineBelowOriginalLine = buffer.lineForRow(2) @@ -3581,18 +4064,27 @@ describe('TextEditor', () => { expect(buffer.lineForRow(1)).toBe(originalLine.slice(0, 6)) expect(buffer.lineForRow(2)).toBe(originalLine.slice(6)) expect(buffer.lineForRow(3)).toBe(lineBelowOriginalLine) - expect(editor.getCursorScreenPosition()).toEqual({row: 2, column: 0}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 2, + column: 0 + }) }) }) describe('when the cursor is on the end of a line', () => { it('inserts an empty line after it', () => { - editor.setCursorScreenPosition({row: 1, column: buffer.lineForRow(1).length}) + editor.setCursorScreenPosition({ + row: 1, + column: buffer.lineForRow(1).length + }) editor.insertNewline() expect(buffer.lineForRow(2)).toBe('') - expect(editor.getCursorScreenPosition()).toEqual({row: 2, column: 0}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 2, + column: 0 + }) }) }) }) @@ -3606,9 +4098,15 @@ describe('TextEditor', () => { editor.insertNewline() expect(editor.lineTextForBufferRow(3)).toBe(' var pivot') - expect(editor.lineTextForBufferRow(4)).toBe(' = items.shift(), current') - expect(editor.lineTextForBufferRow(5)).toBe(', left = [], right = [];') - expect(editor.lineTextForBufferRow(6)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' = items.shift(), current' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ', left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' while(items.length > 0) {' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([4, 0]) @@ -3623,11 +4121,19 @@ describe('TextEditor', () => { editor.insertText('\n') expect(editor.lineTextForBufferRow(3)).toBe('') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(6)).toBe(' current = items.shift();') + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' current = items.shift();' + ) expect(editor.lineTextForBufferRow(7)).toBe('') - expect(editor.lineTextForBufferRow(8)).toBe(' current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(8)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(9)).toBe(' }') const [cursor1, cursor2] = editor.getCursors() @@ -3650,7 +4156,7 @@ describe('TextEditor', () => { }) it("inserts a newline below the cursor's current line, autoindents it, and moves the cursor to the end of the line", () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.insertNewlineBelow() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' ') @@ -3665,7 +4171,9 @@ describe('TextEditor', () => { editor.insertNewlineAbove() expect(editor.getCursorBufferPosition()).toEqual([0, 0]) expect(editor.lineTextForBufferRow(0)).toBe('') - expect(editor.lineTextForBufferRow(1)).toBe('var quicksort = function () {') + expect(editor.lineTextForBufferRow(1)).toBe( + 'var quicksort = function () {' + ) expect(editor.buffer.getLineCount()).toBe(14) }) }) @@ -3676,7 +4184,9 @@ describe('TextEditor', () => { editor.insertNewlineAbove() expect(editor.getCursorBufferPosition()).toEqual([3, 0]) expect(editor.lineTextForBufferRow(3)).toBe('') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.buffer.getLineCount()).toBe(14) editor.undo() @@ -3685,7 +4195,7 @@ describe('TextEditor', () => { }) it('indents the new line to the correct level when editor.autoIndent is true', () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setText(' var test') editor.setCursorBufferPosition([0, 2]) @@ -3718,7 +4228,7 @@ describe('TextEditor', () => { describe('.insertNewLine()', () => { describe('when a new line is appended before a closing tag (e.g. by pressing enter before a selection)', () => { it('moves the line down and keeps the indentation level the same when editor.autoIndent is true', () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setCursorBufferPosition([9, 2]) editor.insertNewline() expect(editor.lineTextForBufferRow(10)).toBe(' };') @@ -3727,7 +4237,7 @@ describe('TextEditor', () => { describe('when a newline is appended with a trailing closing tag behind the cursor (e.g. by pressing enter in the middel of a line)', () => { it('indents the new line to the correct level when editor.autoIndent is true and using a curly-bracket language', () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) atom.grammars.assignLanguageMode(editor, 'source.js') editor.setText('var test = () => {\n return true;};') editor.setCursorBufferPosition([1, 14]) @@ -3738,7 +4248,7 @@ describe('TextEditor', () => { it('indents the new line to the current level when editor.autoIndent is true and no increaseIndentPattern is specified', () => { atom.grammars.assignLanguageMode(editor, null) - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setText(' if true') editor.setCursorBufferPosition([0, 8]) editor.insertNewline() @@ -3749,7 +4259,7 @@ describe('TextEditor', () => { it('indents the new line to the correct level when editor.autoIndent is true and using an off-side rule language', async () => { await atom.packages.activatePackage('language-coffee-script') - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) atom.grammars.assignLanguageMode(editor, 'source.coffee') editor.setText('if true\n return trueelse\n return false') editor.setCursorBufferPosition([1, 13]) @@ -3763,7 +4273,7 @@ describe('TextEditor', () => { describe('when a newline is appended on a line that matches the decreaseNextIndentPattern', () => { it('indents the new line to the correct level when editor.autoIndent is true', async () => { await atom.packages.activatePackage('language-go') - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) atom.grammars.assignLanguageMode(editor, 'source.go') editor.setText('fmt.Printf("some%s",\n "thing")') editor.setCursorBufferPosition([1, 10]) @@ -3780,20 +4290,25 @@ describe('TextEditor', () => { beforeEach(() => { const selection = editor.getLastSelection() - changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler') + changeScreenRangeHandler = jasmine.createSpy( + 'changeScreenRangeHandler' + ) selection.onDidChangeRange(changeScreenRangeHandler) }) describe('when the cursor is on the middle of the line', () => { it('removes the character before the cursor', () => { - editor.setCursorScreenPosition({row: 1, column: 7}) + editor.setCursorScreenPosition({ row: 1, column: 7 }) expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') editor.backspace() const line = buffer.lineForRow(1) expect(line).toBe(' var ort = function(items) {') - expect(editor.getCursorScreenPosition()).toEqual({row: 1, column: 6}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 1, + column: 6 + }) expect(changeScreenRangeHandler).toHaveBeenCalled() }) }) @@ -3804,14 +4319,19 @@ describe('TextEditor', () => { expect(originalLine0).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') - editor.setCursorScreenPosition({row: 1, column: 0}) + editor.setCursorScreenPosition({ row: 1, column: 0 }) editor.backspace() const line0 = buffer.lineForRow(0) const line1 = buffer.lineForRow(1) - expect(line0).toBe('var quicksort = function () { var sort = function(items) {') + expect(line0).toBe( + 'var quicksort = function () { var sort = function(items) {' + ) expect(line1).toBe(' if (items.length <= 1) return items;') - expect(editor.getCursorScreenPosition()).toEqual([0, originalLine0.length]) + expect(editor.getCursorScreenPosition()).toEqual([ + 0, + originalLine0.length + ]) expect(changeScreenRangeHandler).toHaveBeenCalled() }) @@ -3819,7 +4339,7 @@ describe('TextEditor', () => { describe('when the cursor is at the first column of the first line', () => { it("does nothing, but doesn't raise an error", () => { - editor.setCursorScreenPosition({row: 0, column: 0}) + editor.setCursorScreenPosition({ row: 0, column: 0 }) editor.backspace() }) }) @@ -3843,7 +4363,9 @@ describe('TextEditor', () => { editor.backspace() expect(buffer.lineForRow(7)).toBe(' }') - expect(buffer.lineForRow(8)).toBe(' eturn sort(left).concat(pivot).concat(sort(right));') + expect(buffer.lineForRow(8)).toBe( + ' eturn sort(left).concat(pivot).concat(sort(right));' + ) }) }) @@ -3853,7 +4375,9 @@ describe('TextEditor', () => { editor.foldCurrentRow() editor.backspace() - expect(buffer.lineForRow(1)).toBe(' var sort = function(items) var pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.getCursorScreenPosition()).toEqual([1, 29]) }) }) @@ -3867,7 +4391,9 @@ describe('TextEditor', () => { editor.backspace() - expect(editor.lineTextForBufferRow(3)).toBe(' var pivo = items.shift(), curren, left = [], right = [];') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivo = items.shift(), curren, left = [], right = [];' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([3, 12]) @@ -3887,8 +4413,12 @@ describe('TextEditor', () => { editor.backspace() - expect(editor.lineTextForBufferRow(3)).toBe(' var pivo = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' whileitems.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivo = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' whileitems.length > 0) {' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([3, 12]) @@ -3897,8 +4427,7 @@ describe('TextEditor', () => { const [selection1, selection2] = editor.getSelections() expect(selection1.isEmpty()).toBeTruthy() expect(selection2.isEmpty()).toBeTruthy() - }) - ) + })) describe('when the cursors are on the first column of their lines', () => it('removes the newlines preceding each cursor', () => { @@ -3906,16 +4435,21 @@ describe('TextEditor', () => { editor.addCursorAtScreenPosition([6, 0]) editor.backspace() - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items; var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(4)).toBe(' current = items.shift(); current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items; var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' current = items.shift(); current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(5)).toBe(' }') const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([2, 40]) expect(cursor2.getBufferPosition()).toEqual([4, 30]) - }) - ) + })) }) }) @@ -3940,7 +4474,10 @@ describe('TextEditor', () => { describe('when there are multiple selections', () => { it('removes all selected text', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[0, 16], [0, 24]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[0, 16], [0, 24]] + ]) editor.backspace() expect(editor.lineTextForBufferRow(0)).toBe('var = () {') }) @@ -4022,19 +4559,25 @@ describe('TextEditor', () => { editor.deleteToBeginningOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = function(ems) {') - expect(buffer.lineForRow(3)).toBe(' ar pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(3)).toBe( + ' ar pivot = items.shift(), current, left = [], right = [];' + ) expect(cursor1.getBufferPosition()).toEqual([1, 22]) expect(cursor2.getBufferPosition()).toEqual([3, 4]) editor.deleteToBeginningOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = functionems) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return itemsar pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return itemsar pivot = items.shift(), current, left = [], right = [];' + ) expect(cursor1.getBufferPosition()).toEqual([1, 21]) expect(cursor2.getBufferPosition()).toEqual([2, 39]) editor.deleteToBeginningOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = ems) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return ar pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return ar pivot = items.shift(), current, left = [], right = [];' + ) expect(cursor1.getBufferPosition()).toEqual([1, 13]) expect(cursor2.getBufferPosition()).toEqual([2, 34]) @@ -4050,7 +4593,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]]) editor.deleteToBeginningOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = function(it) {') - expect(buffer.lineForRow(2)).toBe('if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'if (items.length <= 1) return items;' + ) }) }) }) @@ -4073,7 +4618,9 @@ describe('TextEditor', () => { it('deletes the next newline', () => { editor.setCursorBufferPosition([1, 30]) editor.deleteToEndOfLine() - expect(buffer.lineForRow(1)).toBe(' var sort = function(items) { if (items.length <= 1) return items;') + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) { if (items.length <= 1) return items;' + ) }) }) }) @@ -4083,7 +4630,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]]) editor.deleteToEndOfLine() expect(buffer.lineForRow(1)).toBe(' var sort = function(it) {') - expect(buffer.lineForRow(2)).toBe('if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'if (items.length <= 1) return items;' + ) }) }) }) @@ -4097,7 +4646,9 @@ describe('TextEditor', () => { editor.deleteToBeginningOfLine() expect(buffer.lineForRow(1)).toBe('ems) {') - expect(buffer.lineForRow(2)).toBe('f (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'f (items.length <= 1) return items;' + ) expect(cursor1.getBufferPosition()).toEqual([1, 0]) expect(cursor2.getBufferPosition()).toEqual([2, 0]) }) @@ -4106,7 +4657,9 @@ describe('TextEditor', () => { it('deletes the newline', () => { editor.setCursorBufferPosition([2]) editor.deleteToBeginningOfLine() - expect(buffer.lineForRow(1)).toBe(' var sort = function(items) { if (items.length <= 1) return items;') + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) { if (items.length <= 1) return items;' + ) }) }) }) @@ -4116,7 +4669,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]]) editor.deleteToBeginningOfLine() expect(buffer.lineForRow(1)).toBe('ems) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) }) }) }) @@ -4135,7 +4690,9 @@ describe('TextEditor', () => { it('joins the line with the following line', () => { editor.setCursorScreenPosition([1, buffer.lineForRow(1).length]) editor.delete() - expect(buffer.lineForRow(1)).toBe(' var sort = function(items) { if (items.length <= 1) return items;') + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) { if (items.length <= 1) return items;' + ) }) }) @@ -4157,7 +4714,9 @@ describe('TextEditor', () => { expect(buffer.lineForRow(3)).toBe(' vae(items.length > 0) {') expect(buffer.lineForRow(4)).toBe(' current = items.shift();') - expect(editor.getCursorScreenPosition()).toEqual(cursorPositionBefore) + expect(editor.getCursorScreenPosition()).toEqual( + cursorPositionBefore + ) }) }) @@ -4169,7 +4728,9 @@ describe('TextEditor', () => { editor.delete() - expect(buffer.lineForRow(3)).toBe(' ar pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(3)).toBe( + ' ar pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.isFoldedAtScreenRow(4)).toBe(true) expect(editor.getCursorScreenPosition()).toEqual([3, 4]) }) @@ -4182,9 +4743,15 @@ describe('TextEditor', () => { editor.delete() - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') - expect(buffer.lineForRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(buffer.lineForRow(4)).toBe(' while ? left.push(current) : right.push(current);') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(buffer.lineForRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(buffer.lineForRow(4)).toBe( + ' while ? left.push(current) : right.push(current);' + ) expect(buffer.lineForRow(5)).toBe(' }') expect(editor.getCursorBufferPosition()).toEqual([4, 9]) }) @@ -4199,7 +4766,9 @@ describe('TextEditor', () => { editor.delete() - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot= items.shift(), current left = [], right = [];') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot= items.shift(), current left = [], right = [];' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([3, 13]) @@ -4219,8 +4788,12 @@ describe('TextEditor', () => { editor.delete() - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot= items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(tems.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot= items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(tems.length > 0) {' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([3, 13]) @@ -4229,8 +4802,7 @@ describe('TextEditor', () => { const [selection1, selection2] = editor.getSelections() expect(selection1.isEmpty()).toBeTruthy() expect(selection2.isEmpty()).toBeTruthy() - }) - ) + })) describe('when the cursors are at the end of their lines', () => it('removes the newlines following each cursor', () => { @@ -4239,13 +4811,14 @@ describe('TextEditor', () => { editor.delete() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () { var sort = function(items) { if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () { var sort = function(items) { if (items.length <= 1) return items;' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([0, 29]) expect(cursor2.getBufferPosition()).toEqual([0, 59]) - }) - ) + })) }) }) @@ -4254,7 +4827,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]]) editor.delete() expect(buffer.lineForRow(1)).toBe(' var sort = function(it) {') - expect(buffer.lineForRow(2)).toBe('if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'if (items.length <= 1) return items;' + ) expect(editor.getLastSelection().isEmpty()).toBeTruthy() }) }) @@ -4262,12 +4837,14 @@ describe('TextEditor', () => { describe('when there are multiple selections', () => describe('when selections are on the same line', () => { it('removes all selected text', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[0, 16], [0, 24]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[0, 16], [0, 24]] + ]) editor.delete() expect(editor.lineTextForBufferRow(0)).toBe('var = () {') }) - }) - ) + })) }) describe('.deleteToEndOfWord()', () => { @@ -4279,13 +4856,17 @@ describe('TextEditor', () => { editor.deleteToEndOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = function(it) {') - expect(buffer.lineForRow(2)).toBe(' i (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' i (items.length <= 1) return items;' + ) expect(cursor1.getBufferPosition()).toEqual([1, 24]) expect(cursor2.getBufferPosition()).toEqual([2, 5]) editor.deleteToEndOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = function(it {') - expect(buffer.lineForRow(2)).toBe(' iitems.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' iitems.length <= 1) return items;' + ) expect(cursor1.getBufferPosition()).toEqual([1, 24]) expect(cursor2.getBufferPosition()).toEqual([2, 5]) }) @@ -4333,8 +4914,7 @@ describe('TextEditor', () => { expect(buffer.lineForRow(0)).not.toMatch(/^\t/) editor.indent() expect(buffer.lineForRow(0)).toMatch(/^\t/) - }) - ) + })) }) describe('when autoIndent is enabled', () => { @@ -4343,7 +4923,7 @@ describe('TextEditor', () => { it('moves the cursor to the end of the leading whitespace and inserts enough whitespace to bring the line to the suggested level of indentation', () => { buffer.insert([5, 0], ' \n') editor.setCursorBufferPosition([5, 0]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(5)).toMatch(/^\s+$/) expect(buffer.lineForRow(5).length).toBe(6) expect(editor.getCursorBufferPosition()).toEqual([5, 6]) @@ -4353,14 +4933,14 @@ describe('TextEditor', () => { editor.setTabLength(4) buffer.insert([12, 2], '\n ') editor.setCursorBufferPosition([13, 1]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(13)).toMatch(/^\s+$/) expect(buffer.lineForRow(13).length).toBe(4) expect(editor.getCursorBufferPosition()).toEqual([13, 4]) buffer.insert([13, 0], ' ') editor.setCursorBufferPosition([13, 6]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(13).length).toBe(8) }) }) @@ -4371,7 +4951,7 @@ describe('TextEditor', () => { editor.setSoftTabs(false) buffer.insert([5, 0], '\t\n') editor.setCursorBufferPosition([5, 0]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(5)).toMatch(/^\t\t\t$/) expect(editor.getCursorBufferPosition()).toEqual([5, 3]) }) @@ -4382,11 +4962,10 @@ describe('TextEditor', () => { buffer.setText(' \ntest') editor.setCursorBufferPosition([1, 0]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(1)).toBe('\ttest') expect(editor.getCursorBufferPosition()).toEqual([1, 1]) - }) - ) + })) }) }) @@ -4395,12 +4974,11 @@ describe('TextEditor', () => { it("moves the cursor to the end of the leading whitespace and inserts 'tabLength' spaces into the buffer", () => { buffer.insert([7, 0], ' \n') editor.setCursorBufferPosition([7, 2]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(7)).toMatch(/^\s+$/) expect(buffer.lineForRow(7).length).toBe(8) expect(editor.getCursorBufferPosition()).toEqual([7, 8]) - }) - ) + })) describe("when 'softTabs' is false", () => it('moves the cursor to the end of the leading whitespace and inserts \t into the buffer', () => { @@ -4408,11 +4986,10 @@ describe('TextEditor', () => { editor.setSoftTabs(false) buffer.insert([7, 0], '\t\t\t\n') editor.setCursorBufferPosition([7, 1]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(7)).toMatch(/^\t\t\t\t$/) expect(editor.getCursorBufferPosition()).toEqual([7, 4]) - }) - ) + })) }) }) }) @@ -4434,12 +5011,18 @@ describe('TextEditor', () => { editor.indent() expect(buffer.lineForRow(0)).toMatch(/^\t/) expect(editor.getCursorBufferPosition()).toEqual([0, 1]) - expect(editor.getCursorScreenPosition()).toEqual([0, editor.getTabLength()]) + expect(editor.getCursorScreenPosition()).toEqual([ + 0, + editor.getTabLength() + ]) editor.indent() expect(buffer.lineForRow(0)).toMatch(/^\t\t/) expect(editor.getCursorBufferPosition()).toEqual([0, 2]) - expect(editor.getCursorScreenPosition()).toEqual([0, editor.getTabLength() * 2]) + expect(editor.getCursorScreenPosition()).toEqual([ + 0, + editor.getTabLength() * 2 + ]) }) }) }) @@ -4456,23 +5039,26 @@ describe('TextEditor', () => { describe('when no text is selected', () => { beforeEach(() => - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[5, 0], [5, 0]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[5, 0], [5, 0]]]) ) it('cuts the lines on which there are cursors', () => { editor.cutSelectedText() expect(buffer.getLineCount()).toBe(11) - expect(buffer.lineForRow(1)).toBe(' if (items.length <= 1) return items;') - expect(buffer.lineForRow(4)).toBe(' current < pivot ? left.push(current) : right.push(current);') - expect(atom.clipboard.read()).toEqual([ - 'var quicksort = function () {', - '', - ' current = items.shift();', - '' - ].join('\n')) + expect(buffer.lineForRow(1)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(buffer.lineForRow(4)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) + expect(atom.clipboard.read()).toEqual( + [ + 'var quicksort = function () {', + '', + ' current = items.shift();', + '' + ].join('\n') + ) }) }) @@ -4497,7 +5083,9 @@ describe('TextEditor', () => { editor.setEditorWidthInChars(25) editor.setCursorScreenPosition([2, 6]) editor.cutToEndOfLine() - expect(editor.lineTextForScreenRow(2)).toBe(' var function(items) {') + expect(editor.lineTextForScreenRow(2)).toBe( + ' var function(items) {' + ) }) }) @@ -4509,19 +5097,26 @@ describe('TextEditor', () => { editor.cutToEndOfLine() expect(buffer.lineForRow(2)).toBe(' if (items.length') expect(buffer.lineForRow(3)).toBe(' var pivot = item') - expect(atom.clipboard.read()).toBe(' <= 1) return items;\ns.shift(), current, left = [], right = [];') - }) - ) + expect(atom.clipboard.read()).toBe( + ' <= 1) return items;\ns.shift(), current, left = [], right = [];' + ) + })) describe('when text is selected', () => it('only cuts the selected text, not to the end of the line', () => { - editor.setSelectedBufferRanges([[[2, 20], [2, 30]], [[3, 20], [3, 20]]]) + editor.setSelectedBufferRanges([ + [[2, 20], [2, 30]], + [[3, 20], [3, 20]] + ]) editor.cutToEndOfLine() - expect(buffer.lineForRow(2)).toBe(' if (items.lengthurn items;') + expect(buffer.lineForRow(2)).toBe( + ' if (items.lengthurn items;' + ) expect(buffer.lineForRow(3)).toBe(' var pivot = item') - expect(atom.clipboard.read()).toBe(' <= 1) ret\ns.shift(), current, left = [], right = [];') - }) - ) + expect(atom.clipboard.read()).toBe( + ' <= 1) ret\ns.shift(), current, left = [], right = [];' + ) + })) }) }) @@ -4538,47 +5133,59 @@ describe('TextEditor', () => { editor.cutToEndOfBufferLine() expect(buffer.lineForRow(2)).toBe(' if (items.length') expect(buffer.lineForRow(3)).toBe(' var pivot = item') - expect(atom.clipboard.read()).toBe(' <= 1) return items;\ns.shift(), current, left = [], right = [];') + expect(atom.clipboard.read()).toBe( + ' <= 1) return items;\ns.shift(), current, left = [], right = [];' + ) }) }) describe('when text is selected', () => { it('only cuts the selected text, not to the end of the buffer line', () => { - editor.setSelectedBufferRanges([[[2, 20], [2, 30]], [[3, 20], [3, 20]]]) + editor.setSelectedBufferRanges([ + [[2, 20], [2, 30]], + [[3, 20], [3, 20]] + ]) editor.cutToEndOfBufferLine() expect(buffer.lineForRow(2)).toBe(' if (items.lengthurn items;') expect(buffer.lineForRow(3)).toBe(' var pivot = item') - expect(atom.clipboard.read()).toBe(' <= 1) ret\ns.shift(), current, left = [], right = [];') + expect(atom.clipboard.read()).toBe( + ' <= 1) ret\ns.shift(), current, left = [], right = [];' + ) }) }) }) describe('.copySelectedText()', () => { it('copies selected text onto the clipboard', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]], [[2, 8], [2, 13]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]], + [[2, 8], [2, 13]] + ]) editor.copySelectedText() - expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') + expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) expect(clipboard.readText()).toBe('quicksort\nsort\nitems') expect(atom.clipboard.read()).toEqual('quicksort\nsort\nitems') }) describe('when no text is selected', () => { beforeEach(() => { - editor.setSelectedBufferRanges([ - [[1, 5], [1, 5]], - [[5, 8], [5, 8]] - ]) + editor.setSelectedBufferRanges([[[1, 5], [1, 5]], [[5, 8], [5, 8]]]) }) it('copies the lines on which there are cursors', () => { editor.copySelectedText() - expect(atom.clipboard.read()).toEqual([ - ' var sort = function(items) {\n', - ' current = items.shift();\n' - ].join('\n')) + expect(atom.clipboard.read()).toEqual( + [ + ' var sort = function(items) {\n', + ' current = items.shift();\n' + ].join('\n') + ) expect(editor.getSelectedBufferRanges()).toEqual([ [[1, 5], [1, 5]], [[5, 8], [5, 8]] @@ -4602,12 +5209,18 @@ describe('TextEditor', () => { describe('.copyOnlySelectedText()', () => { describe('when thee are multiple selections', () => { it('copies selected text onto the clipboard', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]], [[2, 8], [2, 13]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]], + [[2, 8], [2, 13]] + ]) editor.copyOnlySelectedText() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) expect(clipboard.readText()).toBe('quicksort\nsort\nitems') expect(atom.clipboard.read()).toEqual(`quicksort\nsort\nitems`) }) @@ -4623,14 +5236,16 @@ describe('TextEditor', () => { }) describe('.pasteText()', () => { - const copyText = function (text, {startColumn, textEditor} = {}) { + const copyText = function (text, { startColumn, textEditor } = {}) { if (startColumn == null) startColumn = 0 if (textEditor == null) textEditor = editor textEditor.setCursorBufferPosition([0, 0]) textEditor.insertText(text) const numberOfNewlines = text.match(/\n/g).length const endColumn = text.match(/[^\n]*$/)[0].length - textEditor.getLastSelection().setBufferRange([[0, startColumn], [numberOfNewlines, endColumn]]) + textEditor + .getLastSelection() + .setBufferRange([[0, startColumn], [numberOfNewlines, endColumn]]) return textEditor.cutSelectedText() } @@ -4638,13 +5253,17 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) atom.clipboard.write('first') editor.pasteText() - expect(editor.lineTextForBufferRow(0)).toBe('var first = function () {') - expect(editor.lineTextForBufferRow(1)).toBe(' var first = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var first = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + ' var first = function(items) {' + ) }) it('notifies ::onWillInsertText observers', () => { const insertedStrings = [] - editor.onWillInsertText(function ({text, cancel}) { + editor.onWillInsertText(function ({ text, cancel }) { insertedStrings.push(text) cancel() }) @@ -4657,7 +5276,9 @@ describe('TextEditor', () => { it('notifies ::onDidInsertText observers', () => { const insertedStrings = [] - editor.onDidInsertText(({text, range}) => insertedStrings.push(text)) + editor.onDidInsertText(({ text, range }) => + insertedStrings.push(text) + ) atom.clipboard.write('hello') editor.pasteText() @@ -4666,11 +5287,13 @@ describe('TextEditor', () => { }) describe('when `autoIndentOnPaste` is true', () => { - beforeEach(() => editor.update({autoIndentOnPaste: true})) + beforeEach(() => editor.update({ autoIndentOnPaste: true })) describe('when pasting multiple lines before any non-whitespace characters', () => { it('auto-indents the lines spanned by the pasted text, based on the first pasted line', () => { - atom.clipboard.write('a(x);\n b(x);\n c(x);\n', {indentBasis: 0}) + atom.clipboard.write('a(x);\n b(x);\n c(x);\n', { + indentBasis: 0 + }) editor.setCursorBufferPosition([5, 0]) editor.pasteText() @@ -4680,14 +5303,18 @@ describe('TextEditor', () => { expect(editor.lineTextForBufferRow(5)).toBe(' a(x);') expect(editor.lineTextForBufferRow(6)).toBe(' b(x);') expect(editor.lineTextForBufferRow(7)).toBe(' c(x);') - expect(editor.lineTextForBufferRow(8)).toBe(' current = items.shift();') + expect(editor.lineTextForBufferRow(8)).toBe( + ' current = items.shift();' + ) }) it('auto-indents lines with a mix of hard tabs and spaces without removing spaces', () => { editor.setSoftTabs(false) expect(editor.indentationForBufferRow(5)).toBe(3) - atom.clipboard.write('/**\n\t * testing\n\t * indent\n\t **/\n', {indentBasis: 1}) + atom.clipboard.write('/**\n\t * testing\n\t * indent\n\t **/\n', { + indentBasis: 1 + }) editor.setCursorBufferPosition([5, 0]) editor.pasteText() @@ -4701,7 +5328,9 @@ describe('TextEditor', () => { describe('when pasting line(s) above a line that matches the decreaseIndentPattern', () => it('auto-indents based on the pasted line(s) only', () => { - atom.clipboard.write('a(x);\n b(x);\n c(x);\n', {indentBasis: 0}) + atom.clipboard.write('a(x);\n b(x);\n c(x);\n', { + indentBasis: 0 + }) editor.setCursorBufferPosition([7, 0]) editor.pasteText() @@ -4709,19 +5338,21 @@ describe('TextEditor', () => { expect(editor.lineTextForBufferRow(8)).toBe(' b(x);') expect(editor.lineTextForBufferRow(9)).toBe(' c(x);') expect(editor.lineTextForBufferRow(10)).toBe(' }') - }) - ) + })) describe('when pasting a line of text without line ending', () => it('does not auto-indent the text', () => { - atom.clipboard.write('a(x);', {indentBasis: 0}) + atom.clipboard.write('a(x);', { indentBasis: 0 }) editor.setCursorBufferPosition([5, 0]) editor.pasteText() - expect(editor.lineTextForBufferRow(5)).toBe('a(x); current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' current < pivot ? left.push(current) : right.push(current);') - }) - ) + expect(editor.lineTextForBufferRow(5)).toBe( + 'a(x); current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) + })) describe('when pasting on a line after non-whitespace characters', () => it('does not auto-indent the affected line', () => { @@ -4739,12 +5370,11 @@ describe('TextEditor', () => { editor.pasteText() expect(editor.lineTextForBufferRow(1)).toBe(' y(); z();') expect(editor.lineTextForBufferRow(2)).toBe(' h();') - }) - ) + })) }) describe('when `autoIndentOnPaste` is false', () => { - beforeEach(() => editor.update({autoIndentOnPaste: false})) + beforeEach(() => editor.update({ autoIndentOnPaste: false })) describe('when the cursor is indented further than the original copied text', () => it('increases the indentation of the copied lines to match', () => { @@ -4754,10 +5384,13 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([5, 6]) editor.pasteText() - expect(editor.lineTextForBufferRow(5)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(6)).toBe(' if (items.length <= 1) return items;') - }) - ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' if (items.length <= 1) return items;' + ) + })) describe('when the cursor is indented less far than the original copied text', () => it('decreases the indentation of the copied lines to match', () => { @@ -4767,10 +5400,11 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([1, 2]) editor.pasteText() - expect(editor.lineTextForBufferRow(1)).toBe(' current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(1)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(2)).toBe('}') - }) - ) + })) describe('when the first copied line has leading whitespace', () => it("preserves the line's leading whitespace", () => { @@ -4780,16 +5414,22 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([0, 0]) editor.pasteText() - expect(editor.lineTextForBufferRow(0)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(1)).toBe(' current = items.shift();') - }) - ) + expect(editor.lineTextForBufferRow(0)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + ' current = items.shift();' + ) + })) }) describe('when the clipboard has many selections', () => { beforeEach(() => { - editor.update({autoIndentOnPaste: false}) - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) + editor.update({ autoIndentOnPaste: false }) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]] + ]) editor.copySelectedText() }) @@ -4802,17 +5442,25 @@ describe('TextEditor', () => { editor.moveRight() editor.insertText('_') editor.pasteText() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort_quicksort = function () {') - expect(editor.lineTextForBufferRow(1)).toBe(' var sort_sort = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort_quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + ' var sort_sort = function(items) {' + ) }) describe('and the selections count does not match', () => { - beforeEach(() => editor.setSelectedBufferRanges([[[0, 4], [0, 13]]])) + beforeEach(() => + editor.setSelectedBufferRanges([[[0, 4], [0, 13]]]) + ) it('pastes the whole text into the buffer', () => { editor.pasteText() expect(editor.lineTextForBufferRow(0)).toBe('var quicksort') - expect(editor.lineTextForBufferRow(1)).toBe('sort = function () {') + expect(editor.lineTextForBufferRow(1)).toBe( + 'sort = function () {' + ) }) }) }) @@ -4826,8 +5474,12 @@ describe('TextEditor', () => { it("pastes the line above the cursor and retains the cursor's column", () => { editor.pasteText() - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.getCursorBufferPosition()).toEqual([3, 13]) }) }) @@ -4842,35 +5494,47 @@ describe('TextEditor', () => { it('overwrites the selection as with any copied text', () => { editor.setSelectedBufferRange([[1, 2], [1, Infinity]]) editor.pasteText() - expect(editor.lineTextForBufferRow(1)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(1)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.lineTextForBufferRow(2)).toBe('') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.getCursorBufferPosition()).toEqual([2, 0]) - }) - ) + })) describe('when there is no selection', () => it("pastes the line above the cursor and retains the cursor's column", () => { editor.pasteText() - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.getCursorBufferPosition()).toEqual([3, 13]) - }) - ) + })) }) it('respects options that preserve the formatting of the pasted text', () => { - editor.update({autoIndentOnPaste: true}) - atom.clipboard.write('a(x);\n b(x);\r\nc(x);\n', {indentBasis: 0}) + editor.update({ autoIndentOnPaste: true }) + atom.clipboard.write('a(x);\n b(x);\r\nc(x);\n', { indentBasis: 0 }) editor.setCursorBufferPosition([5, 0]) editor.insertText(' ') - editor.pasteText({autoIndent: false, preserveTrailingLineIndentation: true, normalizeLineEndings: false}) + editor.pasteText({ + autoIndent: false, + preserveTrailingLineIndentation: true, + normalizeLineEndings: false + }) expect(editor.lineTextForBufferRow(5)).toBe(' a(x);') expect(editor.lineTextForBufferRow(6)).toBe(' b(x);') expect(editor.buffer.lineEndingForRow(6)).toBe('\r\n') expect(editor.lineTextForBufferRow(7)).toBe('c(x);') - expect(editor.lineTextForBufferRow(8)).toBe(' current = items.shift();') + expect(editor.lineTextForBufferRow(8)).toBe( + ' current = items.shift();' + ) }) }) }) @@ -4882,7 +5546,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[0, 3], [0, 3]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe(' var quicksort = function () {') - expect(editor.getSelectedBufferRange()).toEqual([[0, 3 + editor.getTabLength()], [0, 3 + editor.getTabLength()]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 3 + editor.getTabLength()], + [0, 3 + editor.getTabLength()] + ]) }) }) @@ -4893,7 +5560,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[0, 3], [0, 3]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe('\tvar quicksort = function () {') - expect(editor.getSelectedBufferRange()).toEqual([[0, 3 + 1], [0, 3 + 1]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 3 + 1], + [0, 3 + 1] + ]) }) }) }) @@ -4903,8 +5573,13 @@ describe('TextEditor', () => { it('indents line and retains selection', () => { editor.setSelectedBufferRange([[0, 4], [0, 14]]) editor.indentSelectedRows() - expect(buffer.lineForRow(0)).toBe(`${editor.getTabText()}var quicksort = function () {`) - expect(editor.getSelectedBufferRange()).toEqual([[0, 4 + editor.getTabLength()], [0, 14 + editor.getTabLength()]]) + expect(buffer.lineForRow(0)).toBe( + `${editor.getTabText()}var quicksort = function () {` + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 4 + editor.getTabLength()], + [0, 14 + editor.getTabLength()] + ]) }) }) @@ -4915,7 +5590,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[0, 4], [0, 14]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe('\tvar quicksort = function () {') - expect(editor.getSelectedBufferRange()).toEqual([[0, 4 + 1], [0, 14 + 1]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 4 + 1], + [0, 14 + 1] + ]) }) }) }) @@ -4927,8 +5605,13 @@ describe('TextEditor', () => { editor.indentSelectedRows() expect(buffer.lineForRow(9)).toBe(' };') expect(buffer.lineForRow(10)).toBe('') - expect(buffer.lineForRow(11)).toBe(' return sort(Array.apply(this, arguments));') - expect(editor.getSelectedBufferRange()).toEqual([[9, 1 + editor.getTabLength()], [11, 15 + editor.getTabLength()]]) + expect(buffer.lineForRow(11)).toBe( + ' return sort(Array.apply(this, arguments));' + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [9, 1 + editor.getTabLength()], + [11, 15 + editor.getTabLength()] + ]) }) it('does not indent the last row if the selection ends at column 0', () => { @@ -4936,8 +5619,13 @@ describe('TextEditor', () => { editor.indentSelectedRows() expect(buffer.lineForRow(9)).toBe(' };') expect(buffer.lineForRow(10)).toBe('') - expect(buffer.lineForRow(11)).toBe(' return sort(Array.apply(this, arguments));') - expect(editor.getSelectedBufferRange()).toEqual([[9, 1 + editor.getTabLength()], [11, 0]]) + expect(buffer.lineForRow(11)).toBe( + ' return sort(Array.apply(this, arguments));' + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [9, 1 + editor.getTabLength()], + [11, 0] + ]) }) }) @@ -4949,8 +5637,13 @@ describe('TextEditor', () => { editor.indentSelectedRows() expect(buffer.lineForRow(9)).toBe('\t\t};') expect(buffer.lineForRow(10)).toBe('') - expect(buffer.lineForRow(11)).toBe('\t\treturn sort(Array.apply(this, arguments));') - expect(editor.getSelectedBufferRange()).toEqual([[9, 1 + 1], [11, 15 + 1]]) + expect(buffer.lineForRow(11)).toBe( + '\t\treturn sort(Array.apply(this, arguments));' + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [9, 1 + 1], + [11, 15 + 1] + ]) }) }) }) @@ -4962,7 +5655,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[1, 3], [1, 3]]) editor.outdentSelectedRows() expect(buffer.lineForRow(1)).toBe('var sort = function(items) {') - expect(editor.getSelectedBufferRange()).toEqual([[1, 3 - editor.getTabLength()], [1, 3 - editor.getTabLength()]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [1, 3 - editor.getTabLength()], + [1, 3 - editor.getTabLength()] + ]) }) it('outdents when indent is less than a tab length', () => { @@ -4992,11 +5688,17 @@ describe('TextEditor', () => { it('outdents only up to the first non-space non-tab character', () => { editor.insertText(' \tfoo\t ') editor.outdentSelectedRows() - expect(buffer.lineForRow(0)).toBe('\tfoo\t var quicksort = function () {') + expect(buffer.lineForRow(0)).toBe( + '\tfoo\t var quicksort = function () {' + ) editor.outdentSelectedRows() - expect(buffer.lineForRow(0)).toBe('foo\t var quicksort = function () {') + expect(buffer.lineForRow(0)).toBe( + 'foo\t var quicksort = function () {' + ) editor.outdentSelectedRows() - expect(buffer.lineForRow(0)).toBe('foo\t var quicksort = function () {') + expect(buffer.lineForRow(0)).toBe( + 'foo\t var quicksort = function () {' + ) }) }) @@ -5005,7 +5707,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[1, 4], [1, 14]]) editor.outdentSelectedRows() expect(buffer.lineForRow(1)).toBe('var sort = function(items) {') - expect(editor.getSelectedBufferRange()).toEqual([[1, 4 - editor.getTabLength()], [1, 14 - editor.getTabLength()]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [1, 4 - editor.getTabLength()], + [1, 14 - editor.getTabLength()] + ]) }) }) @@ -5015,9 +5720,16 @@ describe('TextEditor', () => { editor.outdentSelectedRows() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe('var sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') - expect(buffer.lineForRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.getSelectedBufferRange()).toEqual([[0, 1], [3, 15 - editor.getTabLength()]]) + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(buffer.lineForRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 1], + [3, 15 - editor.getTabLength()] + ]) }) it('does not outdent the last line of the selection if it ends at column 0', () => { @@ -5025,8 +5737,12 @@ describe('TextEditor', () => { editor.outdentSelectedRows() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe('var sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') - expect(buffer.lineForRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(buffer.lineForRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.getSelectedBufferRange()).toEqual([[0, 1], [3, 0]]) }) @@ -5079,10 +5795,7 @@ describe('TextEditor', () => { }) it('restores cursors and selections to their states before and after undone and redone changes', () => { - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[1, 0], [1, 3]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[1, 0], [1, 3]]]) editor.insertText('abc') expect(editor.getSelectedBufferRanges()).toEqual([ @@ -5144,21 +5857,35 @@ describe('TextEditor', () => { const selections = editor.getSelections() expect(buffer.lineForRow(1)).toBe(' var = function( {') - expect(editor.getSelectedBufferRanges()).toEqual([[[1, 6], [1, 6]], [[1, 17], [1, 17]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[1, 6], [1, 6]], + [[1, 17], [1, 17]] + ]) editor.undo() - expect(editor.getSelectedBufferRanges()).toEqual([[[1, 6], [1, 6]], [[1, 18], [1, 18]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[1, 6], [1, 6]], + [[1, 18], [1, 18]] + ]) editor.undo() - expect(editor.getSelectedBufferRanges()).toEqual([[[1, 6], [1, 10]], [[1, 22], [1, 27]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[1, 6], [1, 10]], + [[1, 22], [1, 27]] + ]) editor.redo() - expect(editor.getSelectedBufferRanges()).toEqual([[[1, 6], [1, 6]], [[1, 18], [1, 18]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[1, 6], [1, 6]], + [[1, 18], [1, 18]] + ]) }) xit('restores folds after undo and redo', () => { editor.foldBufferRow(1) - editor.setSelectedBufferRange([[1, 0], [10, Infinity]], {preserveFolds: true}) + editor.setSelectedBufferRange([[1, 0], [10, Infinity]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(1)).toBeTruthy() editor.insertText(dedent`\ @@ -5208,9 +5935,9 @@ describe('TextEditor', () => { beforeEach(async () => { editor1 = editor - editor2 = new TextEditor({buffer: editor1.buffer}) + editor2 = new TextEditor({ buffer: editor1.buffer }) - editor1.setText(dedent ` + editor1.setText(dedent` aaaaaa bbbbbb cccccc @@ -5220,12 +5947,16 @@ describe('TextEditor', () => { }) it('[editor.transact] restore selection of change-initiated-editor', () => { - editor1.setCursorBufferPosition([0, 0]); editor1.transact(() => editor1.insertText('1')) - editor2.setCursorBufferPosition([1, 0]); editor2.transact(() => editor2.insertText('2')) - editor1.setCursorBufferPosition([2, 0]); editor1.transact(() => editor1.insertText('3')) - editor2.setCursorBufferPosition([3, 0]); editor2.transact(() => editor2.insertText('4')) + editor1.setCursorBufferPosition([0, 0]) + editor1.transact(() => editor1.insertText('1')) + editor2.setCursorBufferPosition([1, 0]) + editor2.transact(() => editor2.insertText('2')) + editor1.setCursorBufferPosition([2, 0]) + editor1.transact(() => editor1.insertText('3')) + editor2.setCursorBufferPosition([3, 0]) + editor2.transact(() => editor2.insertText('4')) - expect(editor1.getText()).toBe(dedent ` + expect(editor1.getText()).toBe(dedent` 1aaaaaa 2bbbbbb 3cccccc @@ -5234,29 +5965,45 @@ describe('TextEditor', () => { `) editor2.setCursorBufferPosition([4, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged editor1.setCursorBufferPosition([4, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged }) @@ -5267,12 +6014,16 @@ describe('TextEditor', () => { editor.groupChangesSinceCheckpoint(checkpoint) } - editor1.setCursorBufferPosition([0, 0]); transact(editor1, () => editor1.insertText('1')) - editor2.setCursorBufferPosition([1, 0]); transact(editor2, () => editor2.insertText('2')) - editor1.setCursorBufferPosition([2, 0]); transact(editor1, () => editor1.insertText('3')) - editor2.setCursorBufferPosition([3, 0]); transact(editor2, () => editor2.insertText('4')) + editor1.setCursorBufferPosition([0, 0]) + transact(editor1, () => editor1.insertText('1')) + editor2.setCursorBufferPosition([1, 0]) + transact(editor2, () => editor2.insertText('2')) + editor1.setCursorBufferPosition([2, 0]) + transact(editor1, () => editor1.insertText('3')) + editor2.setCursorBufferPosition([3, 0]) + transact(editor2, () => editor2.insertText('4')) - expect(editor1.getText()).toBe(dedent ` + expect(editor1.getText()).toBe(dedent` 1aaaaaa 2bbbbbb 3cccccc @@ -5281,29 +6032,45 @@ describe('TextEditor', () => { `) editor2.setCursorBufferPosition([4, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged editor1.setCursorBufferPosition([4, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged }) }) @@ -5375,7 +6142,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('quicksort') expect(selections[1].getText()).toBe('function') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 3], [0, 12]], [[0, 15], [0, 23]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 3], [0, 12]], + [[0, 15], [0, 23]] + ]) }) it('moves multiple active selections on multiple lines one column to the left', () => { @@ -5389,7 +6159,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('quicksort') expect(selections[1].getText()).toBe('sort') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 3], [0, 12]], [[1, 5], [1, 9]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 3], [0, 12]], + [[1, 5], [1, 9]] + ]) }) describe('when a selection is at the first column of a line', () => { @@ -5405,12 +6178,18 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('var') expect(selections[1].getText()).toBe(' v') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 3]], [[1, 0], [1, 3]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 0], [0, 3]], + [[1, 0], [1, 3]] + ]) }) describe('when multiple selections are active on one line', () => { it('does not change the selection', () => { - editor.setSelectedBufferRanges([[[0, 0], [0, 3]], [[0, 4], [0, 13]]]) + editor.setSelectedBufferRanges([ + [[0, 0], [0, 3]], + [[0, 4], [0, 13]] + ]) const selections = editor.getSelections() expect(selections[0].getText()).toBe('var') @@ -5420,7 +6199,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('var') expect(selections[1].getText()).toBe('quicksort') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 3]], [[0, 4], [0, 13]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 0], [0, 3]], + [[0, 4], [0, 13]] + ]) }) }) }) @@ -5448,7 +6230,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('quicksort') expect(selections[1].getText()).toBe('function') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 5], [0, 14]], [[0, 17], [0, 25]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 5], [0, 14]], + [[0, 17], [0, 25]] + ]) }) it('moves multiple active selections on multiple lines one column to the right', () => { @@ -5462,12 +6247,18 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('quicksort') expect(selections[1].getText()).toBe('sort') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 5], [0, 14]], [[1, 7], [1, 11]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 5], [0, 14]], + [[1, 7], [1, 11]] + ]) }) describe('when a selection is at the last column of a line', () => { it('does not change the selection', () => { - editor.setSelectedBufferRanges([[[2, 34], [2, 40]], [[5, 22], [5, 30]]]) + editor.setSelectedBufferRanges([ + [[2, 34], [2, 40]], + [[5, 22], [5, 30]] + ]) const selections = editor.getSelections() expect(selections[0].getText()).toBe('items;') @@ -5478,12 +6269,18 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('items;') expect(selections[1].getText()).toBe('shift();') - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 34], [2, 40]], [[5, 22], [5, 30]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 34], [2, 40]], + [[5, 22], [5, 30]] + ]) }) describe('when multiple selections are active on one line', () => { it('does not change the selection', () => { - editor.setSelectedBufferRanges([[[2, 27], [2, 33]], [[2, 34], [2, 40]]]) + editor.setSelectedBufferRanges([ + [[2, 27], [2, 33]], + [[2, 34], [2, 40]] + ]) const selections = editor.getSelections() expect(selections[0].getText()).toBe('return') @@ -5493,7 +6290,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('return') expect(selections[1].getText()).toBe('items;') - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 27], [2, 33]], [[2, 34], [2, 40]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 27], [2, 33]], + [[2, 34], [2, 40]] + ]) }) }) }) @@ -5529,7 +6329,7 @@ describe('TextEditor', () => { { name: 'insertNewline', op: (opts = {}) => { - editor.setCursorScreenPosition({row: 1, column: 0}) + editor.setCursorScreenPosition({ row: 1, column: 0 }) editor.insertNewline(opts) } }, @@ -5550,7 +6350,7 @@ describe('TextEditor', () => { { name: 'backspace', op: (opts = {}) => { - editor.setCursorScreenPosition({row: 1, column: 7}) + editor.setCursorScreenPosition({ row: 1, column: 7 }) editor.backspace(opts) } }, @@ -5612,7 +6412,10 @@ describe('TextEditor', () => { { name: 'cutSelectedText', op: (opts = {}) => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]] + ]) editor.cutSelectedText(opts) } }, @@ -5633,7 +6436,10 @@ describe('TextEditor', () => { { name: 'pasteText', op: (opts = {}) => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]] + ]) atom.clipboard.write('first') editor.pasteText(opts) } @@ -5672,7 +6478,7 @@ describe('TextEditor', () => { ] describe('without bypassReadOnly', () => { - for (const {name, op} of modifications) { + for (const { name, op } of modifications) { it(`throws an error on ${name}`, () => { expect(op).toThrow() }) @@ -5680,9 +6486,9 @@ describe('TextEditor', () => { }) describe('with bypassReadOnly', () => { - for (const {name, op} of modifications) { + for (const { name, op } of modifications) { it(`permits ${name}`, () => { - op({bypassReadOnly: true}) + op({ bypassReadOnly: true }) }) } }) @@ -5692,7 +6498,9 @@ describe('TextEditor', () => { describe('reading text', () => { it('.lineTextForScreenRow(row)', () => { editor.foldBufferRow(4) - expect(editor.lineTextForScreenRow(5)).toEqual(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForScreenRow(5)).toEqual( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.lineTextForScreenRow(9)).toEqual('};') expect(editor.lineTextForScreenRow(10)).toBeUndefined() }) @@ -5731,7 +6539,7 @@ describe('TextEditor', () => { expect(buffer.getLineCount()).toBe(count - 2) }) - it("restores cursor position for multiple cursors", () => { + it('restores cursor position for multiple cursors', () => { const line = '0123456789'.repeat(8) editor.setText((line + '\n').repeat(5)) editor.setCursorScreenPosition([0, 5]) @@ -5744,13 +6552,10 @@ describe('TextEditor', () => { expect(cursors[1].getScreenPosition()).toEqual([1, 8]) }) - it("restores cursor position for multiple selections", () => { + it('restores cursor position for multiple selections', () => { const line = '0123456789'.repeat(8) editor.setText((line + '\n').repeat(5)) - editor.setSelectedBufferRanges([ - [[0, 5], [0, 8]], - [[2, 4], [2, 15]] - ]) + editor.setSelectedBufferRanges([[[0, 5], [0, 8]], [[2, 4], [2, 15]]]) editor.deleteLine() const cursors = editor.getCursors() @@ -5762,10 +6567,7 @@ describe('TextEditor', () => { it('deletes a line only once when multiple selections are on the same line', () => { const line1 = buffer.lineForRow(1) const count = buffer.getLineCount() - editor.setSelectedBufferRanges([ - [[0, 1], [0, 2]], - [[0, 4], [0, 5]] - ]) + editor.setSelectedBufferRanges([[[0, 1], [0, 2]], [[0, 4], [0, 5]]]) expect(buffer.lineForRow(0)).not.toBe(line1) editor.deleteLine() @@ -5841,7 +6643,9 @@ describe('TextEditor', () => { expect(buffer.lineForRow(3)).toBe(' while(items.length > 0) {') editor.undo() expect(editor.isFoldedAtScreenRow(4)).toBeTruthy() - expect(buffer.lineForRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) }) }) }) @@ -5853,7 +6657,7 @@ describe('TextEditor', () => { expect(buffer.lineForRow(0)).toBe('123var quicksort = function () {') editor.setCursorBufferPosition([0]) - editor.replaceSelectedText({selectWordIfEmpty: true}, () => 'var') + editor.replaceSelectedText({ selectWordIfEmpty: true }, () => 'var') expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') editor.setCursorBufferPosition([10]) @@ -5941,11 +6745,15 @@ describe('TextEditor', () => { describe('.setTabLength(tabLength)', () => { it('clips atomic soft tabs to the given tab length', () => { expect(editor.getTabLength()).toBe(2) - expect(editor.clipScreenPosition([5, 1], {clipDirection: 'forward'})).toEqual([5, 2]) + expect( + editor.clipScreenPosition([5, 1], { clipDirection: 'forward' }) + ).toEqual([5, 2]) editor.setTabLength(6) expect(editor.getTabLength()).toBe(6) - expect(editor.clipScreenPosition([5, 1], {clipDirection: 'forward'})).toEqual([5, 6]) + expect( + editor.clipScreenPosition([5, 1], { clipDirection: 'forward' }) + ).toEqual([5, 6]) const changeHandler = jasmine.createSpy('changeHandler') editor.onDidChange(changeHandler) @@ -5966,7 +6774,8 @@ describe('TextEditor', () => { expect(editor.indentLevelForLine(' hello')).toBe(1.5) }) - it('returns the indent level when the line has only leading tabs', () => expect(editor.indentLevelForLine('\t\thello')).toBe(2)) + it('returns the indent level when the line has only leading tabs', () => + expect(editor.indentLevelForLine('\t\thello')).toBe(2)) it('returns the indent level based on the character starting the line when the leading whitespace contains both spaces and tabs', () => { expect(editor.indentLevelForLine('\t hello')).toBe(2) @@ -5978,7 +6787,7 @@ describe('TextEditor', () => { }) }) - describe('when the buffer\'s language mode changes', () => { + describe("when the buffer's language mode changes", () => { beforeEach(() => { atom.config.set('core.useTreeSitterParsers', false) }) @@ -5993,7 +6802,9 @@ describe('TextEditor', () => { editor.onDidTokenize(event => events.push(event)) await atom.packages.activatePackage('language-c') - expect(atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.c')).toBe(true) + expect( + atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.c') + ).toBe(true) advanceClock(1) expect(events.length).toBe(1) }) @@ -6003,7 +6814,9 @@ describe('TextEditor', () => { editor.onDidChangeGrammar(grammar => events.push(grammar)) await atom.packages.activatePackage('language-c') - expect(atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.c')).toBe(true) + expect( + atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.c') + ).toBe(true) expect(events.length).toBe(1) expect(events[0].name).toBe('C') }) @@ -6017,7 +6830,7 @@ describe('TextEditor', () => { editor.insertText('\n ') expect(editor.lineTextForBufferRow(2)).toBe(' ') - editor.update({autoIndent: false}) + editor.update({ autoIndent: false }) editor.indent() expect(editor.lineTextForBufferRow(2)).toBe(' ') }) @@ -6025,7 +6838,7 @@ describe('TextEditor', () => { }) describe('when editor.autoIndent is true', () => { - beforeEach(() => editor.update({autoIndent: true})) + beforeEach(() => editor.update({ autoIndent: true })) describe('when `indent` is triggered', () => { it('auto-indents the line', () => { @@ -6033,7 +6846,7 @@ describe('TextEditor', () => { editor.insertText('\n ') expect(editor.lineTextForBufferRow(2)).toBe(' ') - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.indent() expect(editor.lineTextForBufferRow(2)).toBe(' ') }) @@ -6044,7 +6857,9 @@ describe('TextEditor', () => { it('indents the newline to one additional level of indentation beyond the preceding line', () => { editor.setCursorBufferPosition([1, Infinity]) editor.insertText('\n') - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1) + 1) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + 1 + ) }) }) @@ -6052,7 +6867,9 @@ describe('TextEditor', () => { it('indents the new line to the same level as the preceding line', () => { editor.setCursorBufferPosition([5, 14]) editor.insertText('\n') - expect(editor.indentationForBufferRow(6)).toBe(editor.indentationForBufferRow(5)) + expect(editor.indentationForBufferRow(6)).toBe( + editor.indentationForBufferRow(5) + ) }) }) @@ -6082,7 +6899,7 @@ describe('TextEditor', () => { editor.insertText(' var this-line-should-be-indented-more\n') expect(editor.indentationForBufferRow(1)).toBe(1) - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setCursorBufferPosition([2, Infinity]) editor.insertText('\n') expect(editor.indentationForBufferRow(1)).toBe(1) @@ -6107,9 +6924,13 @@ describe('TextEditor', () => { it('decreases the indentation to match that of the preceding line', () => { editor.setCursorBufferPosition([1, Infinity]) editor.insertText('\n') - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1) + 1) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + 1 + ) editor.insertText('}') - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1)) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + ) }) }) @@ -6117,15 +6938,21 @@ describe('TextEditor', () => { it('decreases the indentation to be one level below that of the preceding line', () => { editor.setCursorBufferPosition([3, Infinity]) editor.insertText('\n ') - expect(editor.indentationForBufferRow(4)).toBe(editor.indentationForBufferRow(3)) + expect(editor.indentationForBufferRow(4)).toBe( + editor.indentationForBufferRow(3) + ) editor.insertText('}') - expect(editor.indentationForBufferRow(4)).toBe(editor.indentationForBufferRow(3) - 1) + expect(editor.indentationForBufferRow(4)).toBe( + editor.indentationForBufferRow(3) - 1 + ) }) it("doesn't break when decreasing the indentation on a row that has no indentation", () => { editor.setCursorBufferPosition([12, Infinity]) editor.insertText('\n}; # too many closing brackets!') - expect(editor.lineTextForBufferRow(13)).toBe('}; # too many closing brackets!') + expect(editor.lineTextForBufferRow(13)).toBe( + '}; # too many closing brackets!' + ) }) }) }) @@ -6143,9 +6970,13 @@ describe('TextEditor', () => { describe('when the current line does not match a decrease indent pattern', () => { it('leaves the line unchanged', () => { editor.setCursorBufferPosition([2, 4]) - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1) + 1) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + 1 + ) editor.insertText('foo') - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1) + 1) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + 1 + ) }) }) }) @@ -6153,16 +6984,16 @@ describe('TextEditor', () => { describe('atomic soft tabs', () => { it('skips tab-length runs of leading whitespace when moving the cursor', () => { - editor.update({tabLength: 4, atomicSoftTabs: true}) + editor.update({ tabLength: 4, atomicSoftTabs: true }) editor.setCursorScreenPosition([2, 3]) expect(editor.getCursorScreenPosition()).toEqual([2, 4]) - editor.update({atomicSoftTabs: false}) + editor.update({ atomicSoftTabs: false }) editor.setCursorScreenPosition([2, 3]) expect(editor.getCursorScreenPosition()).toEqual([2, 3]) - editor.update({atomicSoftTabs: true}) + editor.update({ atomicSoftTabs: true }) editor.setCursorScreenPosition([2, 3]) expect(editor.getCursorScreenPosition()).toEqual([2, 4]) }) @@ -6181,7 +7012,7 @@ describe('TextEditor', () => { it('notifies ::onDidDestroy observers when the editor is destroyed', () => { let destroyObserverCalled = false - editor.onDidDestroy(() => destroyObserverCalled = true) + editor.onDidDestroy(() => (destroyObserverCalled = true)) editor.destroy() expect(destroyObserverCalled).toBe(true) @@ -6217,7 +7048,9 @@ describe('TextEditor', () => { editor.insertText(' ') editor.setCursorBufferPosition([0]) editor.joinLines() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () { var sort = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () { var sort = function(items) {' + ) expect(editor.getCursorBufferPosition()).toEqual([0, 29]) }) }) @@ -6227,7 +7060,9 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([9]) editor.joinLines() expect(editor.lineTextForBufferRow(9)).toBe(' };') - expect(editor.lineTextForBufferRow(10)).toBe(' return sort(Array.apply(this, arguments));') + expect(editor.lineTextForBufferRow(10)).toBe( + ' return sort(Array.apply(this, arguments));' + ) expect(editor.getCursorBufferPosition()).toEqual([9, 4]) }) }) @@ -6244,7 +7079,9 @@ describe('TextEditor', () => { it('joins the line below with the current line with no added space', () => { editor.setCursorBufferPosition([10]) editor.joinLines() - expect(editor.lineTextForBufferRow(10)).toBe('return sort(Array.apply(this, arguments));') + expect(editor.lineTextForBufferRow(10)).toBe( + 'return sort(Array.apply(this, arguments));' + ) expect(editor.getCursorBufferPosition()).toEqual([10, 0]) }) }) @@ -6255,7 +7092,9 @@ describe('TextEditor', () => { it('joins the line below with the current line separated by a space and retains the selected text', () => { editor.setSelectedBufferRange([[0, 1], [0, 3]]) editor.joinLines() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () { var sort = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () { var sort = function(items) {' + ) expect(editor.getSelectedBufferRange()).toEqual([[0, 1], [0, 3]]) }) }) @@ -6264,7 +7103,9 @@ describe('TextEditor', () => { it('joins all selected lines separated by a space and retains the selected text', () => { editor.setSelectedBufferRange([[9, 3], [12, 1]]) editor.joinLines() - expect(editor.lineTextForBufferRow(9)).toBe(' }; return sort(Array.apply(this, arguments)); };') + expect(editor.lineTextForBufferRow(9)).toBe( + ' }; return sort(Array.apply(this, arguments)); };' + ) expect(editor.getSelectedBufferRange()).toEqual([[9, 3], [9, 49]]) }) }) @@ -6275,11 +7116,14 @@ describe('TextEditor', () => { it('for each selection, duplicates all buffer lines intersected by the selection', () => { editor.foldBufferRow(4) editor.setCursorBufferPosition([2, 5]) - editor.addSelectionForBufferRange([[3, 0], [8, 0]], {preserveFolds: true}) + editor.addSelectionForBufferRange([[3, 0], [8, 0]], { + preserveFolds: true + }) editor.duplicateLines() - expect(editor.getTextInBufferRange([[2, 0], [13, 5]])).toBe(dedent ` + expect(editor.getTextInBufferRange([[2, 0], [13, 5]])).toBe( + dedent` if (items.length <= 1) return items; if (items.length <= 1) return items; var pivot = items.shift(), current, left = [], right = []; @@ -6292,14 +7136,25 @@ describe('TextEditor', () => { current = items.shift(); current < pivot ? left.push(current) : right.push(current); }\ - `.split('\n').map(l => ` ${l}`).join('\n')) - expect(editor.getSelectedBufferRanges()).toEqual([[[3, 5], [3, 5]], [[9, 0], [14, 0]]]) + ` + .split('\n') + .map(l => ` ${l}`) + .join('\n') + ) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[3, 5], [3, 5]], + [[9, 0], [14, 0]] + ]) // folds are also duplicated expect(editor.isFoldedAtScreenRow(5)).toBe(true) expect(editor.isFoldedAtScreenRow(7)).toBe(true) - expect(editor.lineTextForScreenRow(7)).toBe(` while(items.length > 0) {${editor.displayLayer.foldCharacter}}`) - expect(editor.lineTextForScreenRow(8)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForScreenRow(7)).toBe( + ` while(items.length > 0) {${editor.displayLayer.foldCharacter}}` + ) + expect(editor.lineTextForScreenRow(8)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) }) it('duplicates all folded lines for empty selections on lines containing folds', () => { @@ -6308,7 +7163,8 @@ describe('TextEditor', () => { editor.duplicateLines() - expect(editor.getTextInBufferRange([[2, 0], [11, 5]])).toBe(dedent` + expect(editor.getTextInBufferRange([[2, 0], [11, 5]])).toBe( + dedent` if (items.length <= 1) return items; var pivot = items.shift(), current, left = [], right = []; while(items.length > 0) { @@ -6319,24 +7175,31 @@ describe('TextEditor', () => { current = items.shift(); current < pivot ? left.push(current) : right.push(current); } - `.split('\n').map(l => ` ${l}`).join('\n')) + ` + .split('\n') + .map(l => ` ${l}`) + .join('\n') + ) expect(editor.getSelectedBufferRange()).toEqual([[8, 0], [8, 0]]) }) it('can duplicate the last line of the buffer', () => { editor.setSelectedBufferRange([[11, 0], [12, 2]]) editor.duplicateLines() - expect(editor.getTextInBufferRange([[11, 0], [14, 2]])).toBe(' ' + dedent ` + expect(editor.getTextInBufferRange([[11, 0], [14, 2]])).toBe( + ' ' + + dedent` return sort(Array.apply(this, arguments)); }; return sort(Array.apply(this, arguments)); }; - `.trim()) + `.trim() + ) expect(editor.getSelectedBufferRange()).toEqual([[13, 0], [14, 2]]) }) it('only duplicates lines containing multiple selections once', () => { - editor.setText(dedent ` + editor.setText(dedent` aaaaaa bbbbbb cccccc @@ -6350,7 +7213,7 @@ describe('TextEditor', () => { [[3, 3], [3, 4]] ]) editor.duplicateLines() - expect(editor.getText()).toBe(dedent ` + expect(editor.getText()).toBe(dedent` aaaaaa aaaaaa bbbbbb @@ -6492,13 +7355,17 @@ describe('TextEditor', () => { await atom.packages.activatePackage('language-hyperlink') const grammar = atom.grammars.selectGrammar('text.js') - const {line, tags} = grammar.tokenizeLine('var i; // http://github.com') + const { line, tags } = grammar.tokenizeLine('var i; // http://github.com') const tokens = atom.grammars.decodeTokens(line, tags) expect(tokens[0].value).toBe('var') expect(tokens[0].scopes).toEqual(['source.js', 'storage.type.var.js']) expect(tokens[6].value).toBe('http://github.com') - expect(tokens[6].scopes).toEqual(['source.js', 'comment.line.double-slash.js', 'markup.underline.link.http.hyperlink']) + expect(tokens[6].scopes).toEqual([ + 'source.js', + 'comment.line.double-slash.js', + 'markup.underline.link.http.hyperlink' + ]) }) describe('when the grammar is added', () => { @@ -6507,16 +7374,49 @@ describe('TextEditor', () => { editor.setText('// http://github.com') let tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' http://github.com', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' http://github.com', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + } ]) await atom.packages.activatePackage('language-hyperlink') tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' ', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']}, - {text: 'http://github.com', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--markup syntax--underline syntax--link syntax--http syntax--hyperlink']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + }, + { + text: 'http://github.com', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--markup syntax--underline syntax--link syntax--http syntax--hyperlink' + ] + } ]) }) @@ -6526,28 +7426,106 @@ describe('TextEditor', () => { editor.setText('// SELECT * FROM OCTOCATS') let tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' SELECT * FROM OCTOCATS', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' SELECT * FROM OCTOCATS', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + } ]) await atom.packages.activatePackage('package-with-injection-selector') tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' SELECT * FROM OCTOCATS', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' SELECT * FROM OCTOCATS', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + } ]) await atom.packages.activatePackage('language-sql') tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' ', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']}, - {text: 'SELECT', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--keyword syntax--other syntax--DML syntax--sql']}, - {text: ' ', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']}, - {text: '*', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--keyword syntax--operator syntax--star syntax--sql']}, - {text: ' ', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']}, - {text: 'FROM', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--keyword syntax--other syntax--DML syntax--sql']}, - {text: ' OCTOCATS', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + }, + { + text: 'SELECT', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--keyword syntax--other syntax--DML syntax--sql' + ] + }, + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + }, + { + text: '*', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--keyword syntax--operator syntax--star syntax--sql' + ] + }, + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + }, + { + text: 'FROM', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--keyword syntax--other syntax--DML syntax--sql' + ] + }, + { + text: ' OCTOCATS', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + } ]) }) }) @@ -6574,10 +7552,10 @@ describe('TextEditor', () => { describe('.pageUp/Down()', () => { it('moves the cursor down one page length', () => { - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) const element = editor.getElement() jasmine.attachToDOM(element) - element.style.height = (element.component.getLineHeight() * 5) + 'px' + element.style.height = element.component.getLineHeight() * 5 + 'px' element.measureDimensions() expect(editor.getCursorBufferPosition().row).toBe(0) @@ -6598,10 +7576,10 @@ describe('TextEditor', () => { describe('.selectPageUp/Down()', () => { it('selects one screen height of text up or down', () => { - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) const element = editor.getElement() jasmine.attachToDOM(element) - element.style.height = (element.component.getLineHeight() * 5) + 'px' + element.style.height = element.component.getLineHeight() * 5 + 'px' element.measureDimensions() expect(editor.getCursorBufferPosition().row).toBe(0) @@ -6633,28 +7611,37 @@ describe('TextEditor', () => { editor.onDidRequestAutoscroll(scrollSpy) editor.scrollToScreenPosition([8, 20]) - editor.scrollToScreenPosition([8, 20], {center: true}) - editor.scrollToScreenPosition([8, 20], {center: false, reversed: true}) + editor.scrollToScreenPosition([8, 20], { center: true }) + editor.scrollToScreenPosition([8, 20], { center: false, reversed: true }) - expect(scrollSpy).toHaveBeenCalledWith({screenRange: [[8, 20], [8, 20]], options: {}}) - expect(scrollSpy).toHaveBeenCalledWith({screenRange: [[8, 20], [8, 20]], options: {center: true}}) - expect(scrollSpy).toHaveBeenCalledWith({screenRange: [[8, 20], [8, 20]], options: {center: false, reversed: true}}) + expect(scrollSpy).toHaveBeenCalledWith({ + screenRange: [[8, 20], [8, 20]], + options: {} + }) + expect(scrollSpy).toHaveBeenCalledWith({ + screenRange: [[8, 20], [8, 20]], + options: { center: true } + }) + expect(scrollSpy).toHaveBeenCalledWith({ + screenRange: [[8, 20], [8, 20]], + options: { center: false, reversed: true } + }) }) }) describe('scroll past end', () => { it('returns false by default but can be customized', () => { expect(editor.getScrollPastEnd()).toBe(false) - editor.update({scrollPastEnd: true}) + editor.update({ scrollPastEnd: true }) expect(editor.getScrollPastEnd()).toBe(true) - editor.update({scrollPastEnd: false}) + editor.update({ scrollPastEnd: false }) expect(editor.getScrollPastEnd()).toBe(false) }) it('always returns false when autoHeight is on', () => { - editor.update({autoHeight: true, scrollPastEnd: true}) + editor.update({ autoHeight: true, scrollPastEnd: true }) expect(editor.getScrollPastEnd()).toBe(false) - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) expect(editor.getScrollPastEnd()).toBe(true) }) }) @@ -6663,9 +7650,9 @@ describe('TextEditor', () => { it('returns true by default but can be customized', () => { editor = new TextEditor() expect(editor.getAutoHeight()).toBe(true) - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) expect(editor.getAutoHeight()).toBe(false) - editor.update({autoHeight: true}) + editor.update({ autoHeight: true }) expect(editor.getAutoHeight()).toBe(true) editor.destroy() }) @@ -6674,9 +7661,9 @@ describe('TextEditor', () => { describe('auto width', () => { it('returns false by default but can be customized', () => { expect(editor.getAutoWidth()).toBe(false) - editor.update({autoWidth: true}) + editor.update({ autoWidth: true }) expect(editor.getAutoWidth()).toBe(true) - editor.update({autoWidth: false}) + editor.update({ autoWidth: false }) expect(editor.getAutoWidth()).toBe(false) }) }) @@ -6692,7 +7679,7 @@ describe('TextEditor', () => { it('models placeholderText and emits an event when changed', () => { let handler - editor.onDidChangePlaceholderText(handler = jasmine.createSpy()) + editor.onDidChangePlaceholderText((handler = jasmine.createSpy())) expect(editor.getPlaceholderText()).toBeUndefined() @@ -6738,17 +7725,22 @@ describe('TextEditor', () => { expect(gutter.type).toBe('line-number') }) - it("does not allow a custom gutter with the 'line-number' name.", () => expect(editor.addGutter.bind(editor, {name: 'line-number'})).toThrow()) + it("does not allow a custom gutter with the 'line-number' name.", () => + expect( + editor.addGutter.bind(editor, { name: 'line-number' }) + ).toThrow()) }) describe('::decorateMarker', () => { let marker - beforeEach(() => marker = editor.markBufferRange([[1, 0], [1, 0]])) + beforeEach(() => (marker = editor.markBufferRange([[1, 0], [1, 0]]))) it('reflects an added decoration when one of its custom gutters is decorated.', () => { - const gutter = editor.addGutter({'name': 'custom-gutter'}) - const decoration = gutter.decorateMarker(marker, {class: 'custom-class'}) + const gutter = editor.addGutter({ name: 'custom-gutter' }) + const decoration = gutter.decorateMarker(marker, { + class: 'custom-class' + }) const gutterDecorations = editor.getDecorations({ type: 'gutter', gutterName: 'custom-gutter', @@ -6759,7 +7751,9 @@ describe('TextEditor', () => { }) it('reflects an added decoration when its line-number gutter is decorated.', () => { - const decoration = editor.gutterWithName('line-number').decorateMarker(marker, {class: 'test-class'}) + const decoration = editor + .gutterWithName('line-number') + .decorateMarker(marker, { class: 'test-class' }) const gutterDecorations = editor.getDecorations({ type: 'line-number', gutterName: 'line-number', @@ -6782,14 +7776,14 @@ describe('TextEditor', () => { const lineNumberGutter = editor.gutterWithName('line-number') editor.observeGutters(callback) expect(payloads).toEqual([lineNumberGutter]) - const gutter1 = editor.addGutter({name: 'test-gutter-1'}) + const gutter1 = editor.addGutter({ name: 'test-gutter-1' }) expect(payloads).toEqual([lineNumberGutter, gutter1]) - const gutter2 = editor.addGutter({name: 'test-gutter-2'}) + const gutter2 = editor.addGutter({ name: 'test-gutter-2' }) expect(payloads).toEqual([lineNumberGutter, gutter1, gutter2]) }) it('does not call the callback when a gutter is removed.', () => { - const gutter = editor.addGutter({name: 'test-gutter'}) + const gutter = editor.addGutter({ name: 'test-gutter' }) editor.observeGutters(callback) payloads = [] gutter.destroy() @@ -6800,7 +7794,7 @@ describe('TextEditor', () => { const subscription = editor.observeGutters(callback) payloads = [] subscription.dispose() - editor.addGutter({name: 'test-gutter'}) + editor.addGutter({ name: 'test-gutter' }) expect(payloads).toEqual([]) }) }) @@ -6816,7 +7810,7 @@ describe('TextEditor', () => { it('calls the callback with each newly-added gutter, but not with existing gutters.', () => { editor.onDidAddGutter(callback) expect(payloads).toEqual([]) - const gutter = editor.addGutter({name: 'test-gutter'}) + const gutter = editor.addGutter({ name: 'test-gutter' }) expect(payloads).toEqual([gutter]) }) @@ -6824,7 +7818,7 @@ describe('TextEditor', () => { const subscription = editor.onDidAddGutter(callback) payloads = [] subscription.dispose() - editor.addGutter({name: 'test-gutter'}) + editor.addGutter({ name: 'test-gutter' }) expect(payloads).toEqual([]) }) }) @@ -6838,7 +7832,7 @@ describe('TextEditor', () => { }) it('calls the callback when a gutter is removed.', () => { - const gutter = editor.addGutter({name: 'test-gutter'}) + const gutter = editor.addGutter({ name: 'test-gutter' }) editor.onDidRemoveGutter(callback) expect(payloads).toEqual([]) gutter.destroy() @@ -6846,7 +7840,7 @@ describe('TextEditor', () => { }) it('does not call the callback after the subscription has been disposed.', () => { - const gutter = editor.addGutter({name: 'test-gutter'}) + const gutter = editor.addGutter({ name: 'test-gutter' }) const subscription = editor.onDidRemoveGutter(callback) subscription.dispose() gutter.destroy() @@ -6859,9 +7853,19 @@ describe('TextEditor', () => { describe('::decorateMarker', () => { it('includes the decoration in the object returned from ::decorationsStateForScreenRowRange', () => { const marker = editor.markBufferRange([[2, 4], [6, 8]]) - const decoration = editor.decorateMarker(marker, {type: 'highlight', class: 'foo'}) - expect(editor.decorationsStateForScreenRowRange(0, 5)[decoration.id]).toEqual({ - properties: {id: decoration.id, order: Infinity, type: 'highlight', class: 'foo'}, + const decoration = editor.decorateMarker(marker, { + type: 'highlight', + class: 'foo' + }) + expect( + editor.decorationsStateForScreenRowRange(0, 5)[decoration.id] + ).toEqual({ + properties: { + id: decoration.id, + order: Infinity, + type: 'highlight', + class: 'foo' + }, screenRange: marker.getScreenRange(), bufferRange: marker.getBufferRange(), rangeIsReversed: false @@ -6871,7 +7875,10 @@ describe('TextEditor', () => { it("does not throw errors after the marker's containing layer is destroyed", () => { const layer = editor.addMarkerLayer() const marker = layer.markBufferRange([[2, 4], [6, 8]]) - const decoration = editor.decorateMarker(marker, {type: 'highlight', class: 'foo'}) + const decoration = editor.decorateMarker(marker, { + type: 'highlight', + class: 'foo' + }) layer.destroy() editor.decorationsStateForScreenRowRange(0, 5) }) @@ -6885,71 +7892,105 @@ describe('TextEditor', () => { const layer2 = editor.getBuffer().addMarkerLayer() const marker3 = layer2.markRange([[8, 0], [9, 0]]) - const layer1Decoration1 = editor.decorateMarkerLayer(layer1, {type: 'highlight', class: 'foo'}) - const layer1Decoration2 = editor.decorateMarkerLayer(layer1, {type: 'highlight', class: 'bar'}) - const layer2Decoration = editor.decorateMarkerLayer(layer2, {type: 'highlight', class: 'baz'}) + const layer1Decoration1 = editor.decorateMarkerLayer(layer1, { + type: 'highlight', + class: 'foo' + }) + const layer1Decoration2 = editor.decorateMarkerLayer(layer1, { + type: 'highlight', + class: 'bar' + }) + const layer2Decoration = editor.decorateMarkerLayer(layer2, { + type: 'highlight', + class: 'baz' + }) let decorationState = editor.decorationsStateForScreenRowRange(0, 13) - expect(decorationState[`${layer1Decoration1.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'foo'}, + expect( + decorationState[`${layer1Decoration1.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'foo' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer1Decoration1.id}-${marker2.id}`]).toEqual({ - properties: {type: 'highlight', class: 'foo'}, + expect( + decorationState[`${layer1Decoration1.id}-${marker2.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'foo' }, screenRange: marker2.getRange(), bufferRange: marker2.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer1Decoration2.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer1Decoration2.id}-${marker2.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker2.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker2.getRange(), bufferRange: marker2.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer2Decoration.id}-${marker3.id}`]).toEqual({ - properties: {type: 'highlight', class: 'baz'}, - screenRange: marker3.getRange(), - bufferRange: marker3.getRange(), - rangeIsReversed: false - }) + expect(decorationState[`${layer2Decoration.id}-${marker3.id}`]).toEqual( + { + properties: { type: 'highlight', class: 'baz' }, + screenRange: marker3.getRange(), + bufferRange: marker3.getRange(), + rangeIsReversed: false + } + ) layer1Decoration1.destroy() decorationState = editor.decorationsStateForScreenRowRange(0, 12) - expect(decorationState[`${layer1Decoration1.id}-${marker1.id}`]).toBeUndefined() - expect(decorationState[`${layer1Decoration1.id}-${marker2.id}`]).toBeUndefined() - expect(decorationState[`${layer1Decoration2.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration1.id}-${marker1.id}`] + ).toBeUndefined() + expect( + decorationState[`${layer1Decoration1.id}-${marker2.id}`] + ).toBeUndefined() + expect( + decorationState[`${layer1Decoration2.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer1Decoration2.id}-${marker2.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker2.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker2.getRange(), bufferRange: marker2.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer2Decoration.id}-${marker3.id}`]).toEqual({ - properties: {type: 'highlight', class: 'baz'}, - screenRange: marker3.getRange(), - bufferRange: marker3.getRange(), - rangeIsReversed: false - }) + expect(decorationState[`${layer2Decoration.id}-${marker3.id}`]).toEqual( + { + properties: { type: 'highlight', class: 'baz' }, + screenRange: marker3.getRange(), + bufferRange: marker3.getRange(), + rangeIsReversed: false + } + ) - layer1Decoration2.setPropertiesForMarker(marker1, {type: 'highlight', class: 'quux'}) + layer1Decoration2.setPropertiesForMarker(marker1, { + type: 'highlight', + class: 'quux' + }) decorationState = editor.decorationsStateForScreenRowRange(0, 12) - expect(decorationState[`${layer1Decoration2.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'quux'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'quux' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false @@ -6957,8 +7998,10 @@ describe('TextEditor', () => { layer1Decoration2.setPropertiesForMarker(marker1, null) decorationState = editor.decorationsStateForScreenRowRange(0, 12) - expect(decorationState[`${layer1Decoration2.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false @@ -6969,47 +8012,68 @@ describe('TextEditor', () => { describe('invisibles', () => { beforeEach(() => { - editor.update({showInvisibles: true}) + editor.update({ showInvisibles: true }) }) it('substitutes invisible characters according to the given rules', () => { const previousLineText = editor.lineTextForScreenRow(0) - editor.update({invisibles: {eol: '?'}}) + editor.update({ invisibles: { eol: '?' } }) expect(editor.lineTextForScreenRow(0)).not.toBe(previousLineText) expect(editor.lineTextForScreenRow(0).endsWith('?')).toBe(true) - expect(editor.getInvisibles()).toEqual({eol: '?'}) + expect(editor.getInvisibles()).toEqual({ eol: '?' }) }) it('does not use invisibles if showInvisibles is set to false', () => { - editor.update({invisibles: {eol: '?'}}) + editor.update({ invisibles: { eol: '?' } }) expect(editor.lineTextForScreenRow(0).endsWith('?')).toBe(true) - editor.update({showInvisibles: false}) + editor.update({ showInvisibles: false }) expect(editor.lineTextForScreenRow(0).endsWith('?')).toBe(false) }) }) describe('indent guides', () => { it('shows indent guides when `editor.showIndentGuide` is set to true and the editor is not mini', () => { - editor.update({showIndentGuide: false}) + editor.update({ showIndentGuide: false }) expect(editor.tokensForScreenRow(1).slice(0, 3)).toEqual([ - {text: ' ', scopes: ['syntax--source syntax--js', 'leading-whitespace']}, - {text: 'var', scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type']}, - {text: ' sort ', scopes: ['syntax--source syntax--js']} + { + text: ' ', + scopes: ['syntax--source syntax--js', 'leading-whitespace'] + }, + { + text: 'var', + scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type'] + }, + { text: ' sort ', scopes: ['syntax--source syntax--js'] } ]) - editor.update({showIndentGuide: true}) + editor.update({ showIndentGuide: true }) expect(editor.tokensForScreenRow(1).slice(0, 3)).toEqual([ - {text: ' ', scopes: ['syntax--source syntax--js', 'leading-whitespace indent-guide']}, - {text: 'var', scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type']}, - {text: ' sort ', scopes: ['syntax--source syntax--js']} + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'leading-whitespace indent-guide' + ] + }, + { + text: 'var', + scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type'] + }, + { text: ' sort ', scopes: ['syntax--source syntax--js'] } ]) editor.setMini(true) expect(editor.tokensForScreenRow(1).slice(0, 3)).toEqual([ - {text: ' ', scopes: ['syntax--source syntax--js', 'leading-whitespace']}, - {text: 'var', scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type']}, - {text: ' sort ', scopes: ['syntax--source syntax--js']} + { + text: ' ', + scopes: ['syntax--source syntax--js', 'leading-whitespace'] + }, + { + text: 'var', + scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type'] + }, + { text: ' sort ', scopes: ['syntax--source syntax--js'] } ]) }) }) @@ -7025,11 +8089,13 @@ describe('TextEditor', () => { expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = ') - editor.update({editorWidthInChars: 10}) + editor.update({ editorWidthInChars: 10 }) expect(editor.lineTextForScreenRow(0)).toBe('var ') - editor.update({mini: true}) - expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = function () {') + editor.update({ mini: true }) + expect(editor.lineTextForScreenRow(0)).toBe( + 'var quicksort = function () {' + ) }) }) @@ -7043,13 +8109,14 @@ describe('TextEditor', () => { }) expect(editor.lineTextForScreenRow(1)).toEqual(' 9') - editor.update({softWrapHangingIndentLength: 4}) + editor.update({ softWrapHangingIndentLength: 4 }) expect(editor.lineTextForScreenRow(1)).toEqual(' 9') }) }) describe('::getElement', () => { - it('returns an element', () => expect(editor.getElement() instanceof HTMLElement).toBe(true)) + it('returns an element', () => + expect(editor.getElement() instanceof HTMLElement).toBe(true)) }) describe('setMaxScreenLineLength', () => { @@ -7072,7 +8139,7 @@ describe('TextEditor', () => { describe('.scopeDescriptorForBufferPosition(position)', () => { it('returns a default scope descriptor when no language mode is assigned', () => { - editor = new TextEditor({buffer: new TextBuffer()}) + editor = new TextEditor({ buffer: new TextBuffer() }) const scopeDescriptor = editor.scopeDescriptorForBufferPosition([0, 0]) expect(scopeDescriptor.getScopesArray()).toEqual(['text']) }) @@ -7081,7 +8148,7 @@ describe('TextEditor', () => { describe('.syntaxTreeScopeDescriptorForBufferPosition(position)', () => { it('returns the result of scopeDescriptorForBufferPosition() when textmate language mode is used', async () => { atom.config.set('core.useTreeSitterParsers', false) - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) await atom.packages.activatePackage('language-javascript') let buffer = editor.getBuffer() @@ -7098,7 +8165,9 @@ describe('TextEditor', () => { advanceClock() } - const syntaxTreeeScopeDescriptor = editor.syntaxTreeScopeDescriptorForBufferPosition([4, 17]) + const syntaxTreeeScopeDescriptor = editor.syntaxTreeScopeDescriptorForBufferPosition( + [4, 17] + ) expect(syntaxTreeeScopeDescriptor.getScopesArray()).toEqual([ 'source.js', 'support.variable.property.js' @@ -7106,17 +8175,21 @@ describe('TextEditor', () => { }) it('returns the result of syntaxTreeScopeDescriptorForBufferPosition() when tree-sitter language mode is used', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) await atom.packages.activatePackage('language-javascript') let buffer = editor.getBuffer() - buffer.setLanguageMode(new TreeSitterLanguageMode({ - buffer, - grammar: atom.grammars.grammarForScopeName('source.js') - })) + buffer.setLanguageMode( + new TreeSitterLanguageMode({ + buffer, + grammar: atom.grammars.grammarForScopeName('source.js') + }) + ) - const syntaxTreeeScopeDescriptor = editor.syntaxTreeScopeDescriptorForBufferPosition([4, 17]) + const syntaxTreeeScopeDescriptor = editor.syntaxTreeScopeDescriptorForBufferPosition( + [4, 17] + ) expect(syntaxTreeeScopeDescriptor.getScopesArray()).toEqual([ 'source.js', 'program', @@ -7154,7 +8227,9 @@ describe('TextEditor', () => { editor.setText('changed') atom.workspace.getActivePane().splitRight() - const editor2 = await atom.workspace.open('sample.js', {autoIndent: false}) + const editor2 = await atom.workspace.open('sample.js', { + autoIndent: false + }) expect(editor.shouldPromptToSave()).toBeFalsy() editor2.destroy() @@ -7169,20 +8244,40 @@ describe('TextEditor', () => { editor.setText('other stuff') fs.writeFileSync(editor.getPath(), 'new stuff') - expect(editor.shouldPromptToSave({windowCloseRequested: true, projectHasPaths: true})).toBeFalsy() + expect( + editor.shouldPromptToSave({ + windowCloseRequested: true, + projectHasPaths: true + }) + ).toBeFalsy() await new Promise(resolve => editor.onDidConflict(resolve)) - expect(editor.shouldPromptToSave({windowCloseRequested: true, projectHasPaths: true})).toBeTruthy() + expect( + editor.shouldPromptToSave({ + windowCloseRequested: true, + projectHasPaths: true + }) + ).toBeTruthy() }) it('returns false when the window is closing and the project has one or more directory paths', () => { editor.setText('changed') - expect(editor.shouldPromptToSave({windowCloseRequested: true, projectHasPaths: true})).toBeFalsy() + expect( + editor.shouldPromptToSave({ + windowCloseRequested: true, + projectHasPaths: true + }) + ).toBeFalsy() }) it('returns false when the window is closing and the project has no directory paths', () => { editor.setText('changed') - expect(editor.shouldPromptToSave({windowCloseRequested: true, projectHasPaths: false})).toBeTruthy() + expect( + editor.shouldPromptToSave({ + windowCloseRequested: true, + projectHasPaths: false + }) + ).toBeTruthy() }) }) @@ -7196,63 +8291,105 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[4, 5], [7, 5]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(4)).toBe(' // while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' // current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' // current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' // while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' // current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' // current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' // }') expect(editor.getSelectedBufferRange()).toEqual([[4, 8], [7, 8]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' }') }) it('does not comment the last line of a non-empty selection if it ends at column 0', () => { editor.setSelectedBufferRange([[4, 5], [7, 0]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(4)).toBe(' // while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' // current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' // current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' // while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' // current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' // current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' }') }) it('uncomments lines if all lines match the comment regex', () => { editor.setSelectedBufferRange([[0, 0], [0, 1]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('// var quicksort = function () {') + expect(editor.lineTextForBufferRow(0)).toBe( + '// var quicksort = function () {' + ) editor.setSelectedBufferRange([[0, 0], [2, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('// // var quicksort = function () {') - expect(editor.lineTextForBufferRow(1)).toBe('// var sort = function(items) {') - expect(editor.lineTextForBufferRow(2)).toBe('// if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(0)).toBe( + '// // var quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + '// var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + '// if (items.length <= 1) return items;' + ) editor.setSelectedBufferRange([[0, 0], [2, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('// var quicksort = function () {') - expect(editor.lineTextForBufferRow(1)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(0)).toBe( + '// var quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) editor.setSelectedBufferRange([[0, 0], [0, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () {' + ) }) it('uncomments commented lines separated by an empty line', () => { editor.setSelectedBufferRange([[0, 0], [1, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('// var quicksort = function () {') - expect(editor.lineTextForBufferRow(1)).toBe('// var sort = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + '// var quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + '// var sort = function(items) {' + ) editor.getBuffer().insert([0, Infinity], '\n') editor.setSelectedBufferRange([[0, 0], [2, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () {' + ) expect(editor.lineTextForBufferRow(1)).toBe('') - expect(editor.lineTextForBufferRow(2)).toBe(' var sort = function(items) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var sort = function(items) {' + ) }) it('preserves selection emptiness', () => { @@ -7262,7 +8399,9 @@ describe('TextEditor', () => { }) it('does not explode if the current language mode has no comment regex', () => { - const editor = new TextEditor({buffer: new TextBuffer({text: 'hello'})}) + const editor = new TextEditor({ + buffer: new TextBuffer({ text: 'hello' }) + }) editor.setSelectedBufferRange([[0, 0], [0, 5]]) editor.toggleLineCommentsInSelection() expect(editor.lineTextForBufferRow(0)).toBe('hello') @@ -7340,35 +8479,50 @@ describe('TextEditor', () => { expect(editor.lineTextForBufferRow(0)).toBe('/* body {') expect(editor.lineTextForBufferRow(1)).toBe(' font-size: 1234px; */') expect(editor.lineTextForBufferRow(2)).toBe(' width: 110%;') - expect(editor.lineTextForBufferRow(3)).toBe(' font-weight: bold !important;') + expect(editor.lineTextForBufferRow(3)).toBe( + ' font-weight: bold !important;' + ) editor.toggleLineCommentsForBufferRows(2, 2) expect(editor.lineTextForBufferRow(0)).toBe('/* body {') expect(editor.lineTextForBufferRow(1)).toBe(' font-size: 1234px; */') expect(editor.lineTextForBufferRow(2)).toBe(' /* width: 110%; */') - expect(editor.lineTextForBufferRow(3)).toBe(' font-weight: bold !important;') + expect(editor.lineTextForBufferRow(3)).toBe( + ' font-weight: bold !important;' + ) editor.toggleLineCommentsForBufferRows(0, 1) expect(editor.lineTextForBufferRow(0)).toBe('body {') expect(editor.lineTextForBufferRow(1)).toBe(' font-size: 1234px;') expect(editor.lineTextForBufferRow(2)).toBe(' /* width: 110%; */') - expect(editor.lineTextForBufferRow(3)).toBe(' font-weight: bold !important;') + expect(editor.lineTextForBufferRow(3)).toBe( + ' font-weight: bold !important;' + ) }) it('uncomments lines with leading whitespace', () => { - editor.setTextInBufferRange([[2, 0], [2, Infinity]], ' /* width: 110%; */') + editor.setTextInBufferRange( + [[2, 0], [2, Infinity]], + ' /* width: 110%; */' + ) editor.toggleLineCommentsForBufferRows(2, 2) expect(editor.lineTextForBufferRow(2)).toBe(' width: 110%;') }) it('uncomments lines with trailing whitespace', () => { - editor.setTextInBufferRange([[2, 0], [2, Infinity]], '/* width: 110%; */ ') + editor.setTextInBufferRange( + [[2, 0], [2, Infinity]], + '/* width: 110%; */ ' + ) editor.toggleLineCommentsForBufferRows(2, 2) expect(editor.lineTextForBufferRow(2)).toBe('width: 110%; ') }) it('uncomments lines with leading and trailing whitespace', () => { - editor.setTextInBufferRange([[2, 0], [2, Infinity]], ' /* width: 110%; */ ') + editor.setTextInBufferRange( + [[2, 0], [2, Infinity]], + ' /* width: 110%; */ ' + ) editor.toggleLineCommentsForBufferRows(2, 2) expect(editor.lineTextForBufferRow(2)).toBe(' width: 110%; ') }) @@ -7382,7 +8536,9 @@ describe('TextEditor', () => { it('comments/uncomments lines in the given range', () => { editor.toggleLineCommentsForBufferRows(4, 6) - expect(editor.lineTextForBufferRow(4)).toBe(' # pivot = items.shift()') + expect(editor.lineTextForBufferRow(4)).toBe( + ' # pivot = items.shift()' + ) expect(editor.lineTextForBufferRow(5)).toBe(' # left = []') expect(editor.lineTextForBufferRow(6)).toBe(' # right = []') @@ -7394,7 +8550,9 @@ describe('TextEditor', () => { it('comments/uncomments empty lines', () => { editor.toggleLineCommentsForBufferRows(4, 7) - expect(editor.lineTextForBufferRow(4)).toBe(' # pivot = items.shift()') + expect(editor.lineTextForBufferRow(4)).toBe( + ' # pivot = items.shift()' + ) expect(editor.lineTextForBufferRow(5)).toBe(' # left = []') expect(editor.lineTextForBufferRow(6)).toBe(' # right = []') expect(editor.lineTextForBufferRow(7)).toBe(' # ') @@ -7415,15 +8573,27 @@ describe('TextEditor', () => { it('comments/uncomments lines in the given range', () => { editor.toggleLineCommentsForBufferRows(4, 7) - expect(editor.lineTextForBufferRow(4)).toBe(' // while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' // current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' // current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' // while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' // current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' // current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' // }') editor.toggleLineCommentsForBufferRows(4, 5) - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' // current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' // current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' // }') editor.setText('\tvar i;') @@ -7462,7 +8632,7 @@ describe('TextEditor', () => { }) it('maintains cursor buffer position when a folding/unfolding', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) editor.setCursorBufferPosition([5, 5]) editor.foldAll() expect(editor.getCursorBufferPosition()).toEqual([5, 5]) @@ -7470,7 +8640,7 @@ describe('TextEditor', () => { describe('.unfoldAll()', () => { it('unfolds every folded line', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) const initialScreenLineCount = editor.getScreenLineCount() editor.foldBufferRow(0) @@ -7481,7 +8651,9 @@ describe('TextEditor', () => { }) it('unfolds every folded line with comments', async () => { - editor = await atom.workspace.open('sample-with-comments.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-comments.js', { + autoIndent: false + }) const initialScreenLineCount = editor.getScreenLineCount() editor.foldBufferRow(0) @@ -7494,7 +8666,7 @@ describe('TextEditor', () => { describe('.foldAll()', () => { it('folds every foldable line', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) editor.foldAll() const [fold1, fold2, fold3] = editor.unfoldAll() @@ -7568,26 +8740,40 @@ describe('TextEditor', () => { describe('.foldAllAtIndentLevel(indentLevel)', () => { it('folds blocks of text at the given indentation level', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) editor.foldAllAtIndentLevel(0) - expect(editor.lineTextForScreenRow(0)).toBe(`var quicksort = function () {${editor.displayLayer.foldCharacter}};`) + expect(editor.lineTextForScreenRow(0)).toBe( + `var quicksort = function () {${editor.displayLayer.foldCharacter}};` + ) expect(editor.getLastScreenRow()).toBe(0) editor.foldAllAtIndentLevel(1) - expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = function () {') - expect(editor.lineTextForScreenRow(1)).toBe(` var sort = function(items) {${editor.displayLayer.foldCharacter}};`) + expect(editor.lineTextForScreenRow(0)).toBe( + 'var quicksort = function () {' + ) + expect(editor.lineTextForScreenRow(1)).toBe( + ` var sort = function(items) {${editor.displayLayer.foldCharacter}};` + ) expect(editor.getLastScreenRow()).toBe(4) editor.foldAllAtIndentLevel(2) - expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = function () {') - expect(editor.lineTextForScreenRow(1)).toBe(' var sort = function(items) {') - expect(editor.lineTextForScreenRow(2)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForScreenRow(0)).toBe( + 'var quicksort = function () {' + ) + expect(editor.lineTextForScreenRow(1)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForScreenRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.getLastScreenRow()).toBe(9) }) it('does not fold anything but the indentLevel', async () => { - editor = await atom.workspace.open('sample-with-comments.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-comments.js', { + autoIndent: false + }) editor.foldAllAtIndentLevel(0) const folds = editor.unfoldAll() diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index 47b79af2d..3b1aae9b5 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -1,10 +1,17 @@ const NullGrammar = require('../src/null-grammar') const TextMateLanguageMode = require('../src/text-mate-language-mode') const TextBuffer = require('text-buffer') -const {Point, Range} = TextBuffer +const { Point, Range } = TextBuffer const _ = require('underscore-plus') const dedent = require('dedent') -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') describe('TextMateLanguageMode', () => { let languageMode, buffer, config @@ -40,15 +47,15 @@ describe('TextMateLanguageMode', () => { // It treats the entire line as one big token let iterator = languageMode.buildHighlightIterator() - iterator.seek({row: 0, column: 0}) + iterator.seek({ row: 0, column: 0 }) iterator.moveToSuccessor() - expect(iterator.getPosition()).toEqual({row: 0, column: 7}) + expect(iterator.getPosition()).toEqual({ row: 0, column: 7 }) buffer.insert([0, 0], 'hey"') iterator = languageMode.buildHighlightIterator() - iterator.seek({row: 0, column: 0}) + iterator.seek({ row: 0, column: 0 }) iterator.moveToSuccessor() - expect(iterator.getPosition()).toEqual({row: 0, column: 11}) + expect(iterator.getPosition()).toEqual({ row: 0, column: 11 }) }) }) @@ -56,7 +63,12 @@ describe('TextMateLanguageMode', () => { describe('when the buffer is destroyed', () => { beforeEach(() => { buffer = atom.project.bufferForPathSync('sample.js') - languageMode = new TextMateLanguageMode({buffer, config, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) languageMode.startTokenizing() }) @@ -71,7 +83,11 @@ describe('TextMateLanguageMode', () => { describe('when the buffer contains soft-tabs', () => { beforeEach(() => { buffer = atom.project.bufferForPathSync('sample.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) buffer.setLanguageMode(languageMode) languageMode.startTokenizing() }) @@ -105,8 +121,7 @@ describe('TextMateLanguageMode', () => { advanceClock() expect(languageMode.tokenizedLines[10].ruleStack != null).toBeTruthy() expect(languageMode.tokenizedLines[12].ruleStack != null).toBeTruthy() - }) - ) + })) describe('when the buffer is partially tokenized', () => { beforeEach(() => { @@ -168,22 +183,44 @@ describe('TextMateLanguageMode', () => { it('updates tokens to reflect the change', () => { buffer.setTextInRange([[0, 0], [2, 0]], 'foo()\n7\n') - expect(languageMode.tokenizedLines[0].tokens[1]).toEqual({value: '(', scopes: ['source.js', 'meta.function-call.js', 'meta.arguments.js', 'punctuation.definition.arguments.begin.bracket.round.js']}) - expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({value: '7', scopes: ['source.js', 'constant.numeric.decimal.js']}) + expect(languageMode.tokenizedLines[0].tokens[1]).toEqual({ + value: '(', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'meta.arguments.js', + 'punctuation.definition.arguments.begin.bracket.round.js' + ] + }) + expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({ + value: '7', + scopes: ['source.js', 'constant.numeric.decimal.js'] + }) // line 2 is unchanged - expect(languageMode.tokenizedLines[2].tokens[1]).toEqual({value: 'if', scopes: ['source.js', 'keyword.control.js']}) + expect(languageMode.tokenizedLines[2].tokens[1]).toEqual({ + value: 'if', + scopes: ['source.js', 'keyword.control.js'] + }) }) describe('when the change invalidates the tokenization of subsequent lines', () => { it('schedules the invalidated lines to be tokenized in the background', () => { buffer.insert([5, 30], '/* */') buffer.insert([2, 0], '/*') - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js']) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual( + ['source.js'] + ) advanceClock() - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual( + ['source.js', 'comment.block.js'] + ) + expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual( + ['source.js', 'comment.block.js'] + ) + expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual( + ['source.js', 'comment.block.js'] + ) }) }) @@ -192,7 +229,10 @@ describe('TextMateLanguageMode', () => { buffer.insert([5, 0], '*/') buffer.insert([1, 0], 'var ') - expect(languageMode.tokenizedLines[1].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) + expect(languageMode.tokenizedLines[1].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) }) }) @@ -201,16 +241,38 @@ describe('TextMateLanguageMode', () => { buffer.setTextInRange([[1, 0], [3, 0]], 'foo()') // previous line 0 remains - expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({value: 'var', scopes: ['source.js', 'storage.type.var.js']}) + expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ + value: 'var', + scopes: ['source.js', 'storage.type.var.js'] + }) // previous line 3 should be combined with input to form line 1 - expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({value: 'foo', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) - expect(languageMode.tokenizedLines[1].tokens[6]).toEqual({value: '=', scopes: ['source.js', 'keyword.operator.assignment.js']}) + expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({ + value: 'foo', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) + expect(languageMode.tokenizedLines[1].tokens[6]).toEqual({ + value: '=', + scopes: ['source.js', 'keyword.operator.assignment.js'] + }) // lines below deleted regions should be shifted upward - expect(languageMode.tokenizedLines[2].tokens[1]).toEqual({value: 'while', scopes: ['source.js', 'keyword.control.js']}) - expect(languageMode.tokenizedLines[3].tokens[1]).toEqual({value: '=', scopes: ['source.js', 'keyword.operator.assignment.js']}) - expect(languageMode.tokenizedLines[4].tokens[1]).toEqual({value: '<', scopes: ['source.js', 'keyword.operator.comparison.js']}) + expect(languageMode.tokenizedLines[2].tokens[1]).toEqual({ + value: 'while', + scopes: ['source.js', 'keyword.control.js'] + }) + expect(languageMode.tokenizedLines[3].tokens[1]).toEqual({ + value: '=', + scopes: ['source.js', 'keyword.operator.assignment.js'] + }) + expect(languageMode.tokenizedLines[4].tokens[1]).toEqual({ + value: '<', + scopes: ['source.js', 'keyword.operator.comparison.js'] + }) }) }) @@ -218,33 +280,85 @@ describe('TextMateLanguageMode', () => { it('schedules the invalidated lines to be tokenized in the background', () => { buffer.insert([5, 30], '/* */') buffer.setTextInRange([[2, 0], [3, 0]], '/*') - expect(languageMode.tokenizedLines[2].tokens[0].scopes).toEqual(['source.js', 'comment.block.js', 'punctuation.definition.comment.begin.js']) - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js']) + expect(languageMode.tokenizedLines[2].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js', + 'punctuation.definition.comment.begin.js' + ]) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual([ + 'source.js' + ]) advanceClock() - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) }) }) describe('when lines are both updated and inserted', () => { it('updates tokens to reflect the change', () => { - buffer.setTextInRange([[1, 0], [2, 0]], 'foo()\nbar()\nbaz()\nquux()') + buffer.setTextInRange( + [[1, 0], [2, 0]], + 'foo()\nbar()\nbaz()\nquux()' + ) // previous line 0 remains - expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ value: 'var', scopes: ['source.js', 'storage.type.var.js']}) + expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ + value: 'var', + scopes: ['source.js', 'storage.type.var.js'] + }) // 3 new lines inserted - expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({value: 'foo', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) - expect(languageMode.tokenizedLines[2].tokens[0]).toEqual({value: 'bar', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) - expect(languageMode.tokenizedLines[3].tokens[0]).toEqual({value: 'baz', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) + expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({ + value: 'foo', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) + expect(languageMode.tokenizedLines[2].tokens[0]).toEqual({ + value: 'bar', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) + expect(languageMode.tokenizedLines[3].tokens[0]).toEqual({ + value: 'baz', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) // previous line 2 is joined with quux() on line 4 - expect(languageMode.tokenizedLines[4].tokens[0]).toEqual({value: 'quux', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) - expect(languageMode.tokenizedLines[4].tokens[4]).toEqual({value: 'if', scopes: ['source.js', 'keyword.control.js']}) + expect(languageMode.tokenizedLines[4].tokens[0]).toEqual({ + value: 'quux', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) + expect(languageMode.tokenizedLines[4].tokens[4]).toEqual({ + value: 'if', + scopes: ['source.js', 'keyword.control.js'] + }) // previous line 3 is pushed down to become line 5 - expect(languageMode.tokenizedLines[5].tokens[3]).toEqual({value: '=', scopes: ['source.js', 'keyword.operator.assignment.js']}) + expect(languageMode.tokenizedLines[5].tokens[3]).toEqual({ + value: '=', + scopes: ['source.js', 'keyword.operator.assignment.js'] + }) }) }) @@ -252,31 +366,66 @@ describe('TextMateLanguageMode', () => { it('schedules the invalidated lines to be tokenized in the background', () => { buffer.insert([5, 30], '/* */') buffer.insert([2, 0], '/*\nabcde\nabcder') - expect(languageMode.tokenizedLines[2].tokens[0].scopes).toEqual(['source.js', 'comment.block.js', 'punctuation.definition.comment.begin.js']) - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual(['source.js']) + expect(languageMode.tokenizedLines[2].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js', + 'punctuation.definition.comment.begin.js' + ]) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual([ + 'source.js' + ]) advanceClock() // tokenize invalidated lines in background - expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[6].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[7].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[8].tokens[0].scopes).not.toBe(['source.js', 'comment.block.js']) + expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[6].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[7].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[8].tokens[0].scopes).not.toBe([ + 'source.js', + 'comment.block.js' + ]) }) }) }) describe('when there is an insertion that is larger than the chunk size', () => { it('tokenizes the initial chunk synchronously, then tokenizes the remaining lines in the background', () => { - const commentBlock = _.multiplyString('// a comment\n', languageMode.chunkSize + 2) + const commentBlock = _.multiplyString( + '// a comment\n', + languageMode.chunkSize + 2 + ) buffer.insert([0, 0], commentBlock) - expect(languageMode.tokenizedLines[0].ruleStack != null).toBeTruthy() - expect(languageMode.tokenizedLines[4].ruleStack != null).toBeTruthy() + expect( + languageMode.tokenizedLines[0].ruleStack != null + ).toBeTruthy() + expect( + languageMode.tokenizedLines[4].ruleStack != null + ).toBeTruthy() expect(languageMode.tokenizedLines[5]).toBeUndefined() advanceClock() - expect(languageMode.tokenizedLines[5].ruleStack != null).toBeTruthy() - expect(languageMode.tokenizedLines[6].ruleStack != null).toBeTruthy() + expect( + languageMode.tokenizedLines[5].ruleStack != null + ).toBeTruthy() + expect( + languageMode.tokenizedLines[6].ruleStack != null + ).toBeTruthy() }) }) }) @@ -287,7 +436,11 @@ describe('TextMateLanguageMode', () => { atom.packages.activatePackage('language-coffee-script') buffer = atom.project.bufferForPathSync('sample-with-tabs.coffee') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.coffee')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.coffee') + }) languageMode.startTokenizing() }) @@ -328,7 +481,9 @@ describe('TextMateLanguageMode', () => { let tokenizationCount = 0 const editor = await atom.workspace.open('coffee.coffee') - editor.onDidTokenize(() => { tokenizationCount++ }) + editor.onDidTokenize(() => { + tokenizationCount++ + }) fullyTokenize(editor.getBuffer().getLanguageMode()) tokenizationCount = 0 @@ -344,7 +499,11 @@ describe('TextMateLanguageMode', () => { buffer = atom.project.bufferForPathSync() buffer.setText("
<%= User.find(2).full_name %>
") - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.selectGrammar('test.erb')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.selectGrammar('test.erb') + }) fullyTokenize(languageMode) expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ value: "
", @@ -355,7 +514,11 @@ describe('TextMateLanguageMode', () => { fullyTokenize(languageMode) expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ value: '<', - scopes: ['text.html.ruby', 'meta.tag.block.div.html', 'punctuation.definition.tag.begin.html'] + scopes: [ + 'text.html.ruby', + 'meta.tag.block.div.html', + 'punctuation.definition.tag.begin.html' + ] }) }) }) @@ -363,9 +526,11 @@ describe('TextMateLanguageMode', () => { describe('when the buffer is configured with the null grammar', () => { it('does not actually tokenize using the grammar', () => { spyOn(NullGrammar, 'tokenizeLine').andCallThrough() - buffer = atom.project.bufferForPathSync('sample.will-use-the-null-grammar') + buffer = atom.project.bufferForPathSync( + 'sample.will-use-the-null-grammar' + ) buffer.setText('a\nb\nc') - languageMode = new TextMateLanguageMode({buffer, config}) + languageMode = new TextMateLanguageMode({ buffer, config }) const tokenizeCallback = jasmine.createSpy('onDidTokenize') languageMode.onDidTokenize(tokenizeCallback) @@ -393,35 +558,64 @@ describe('TextMateLanguageMode', () => { it('returns the correct token (regression)', () => { buffer = atom.project.bufferForPathSync('sample.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) fullyTokenize(languageMode) - expect(languageMode.tokenForPosition([1, 0]).scopes).toEqual(['source.js']) - expect(languageMode.tokenForPosition([1, 1]).scopes).toEqual(['source.js']) - expect(languageMode.tokenForPosition([1, 2]).scopes).toEqual(['source.js', 'storage.type.var.js']) + expect(languageMode.tokenForPosition([1, 0]).scopes).toEqual([ + 'source.js' + ]) + expect(languageMode.tokenForPosition([1, 1]).scopes).toEqual([ + 'source.js' + ]) + expect(languageMode.tokenForPosition([1, 2]).scopes).toEqual([ + 'source.js', + 'storage.type.var.js' + ]) }) }) describe('.bufferRangeForScopeAtPosition(selector, position)', () => { beforeEach(() => { buffer = atom.project.bufferForPathSync('sample.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) fullyTokenize(languageMode) }) describe('when the selector does not match the token at the position', () => - it('returns a falsy value', () => expect(languageMode.bufferRangeForScopeAtPosition('.bogus', [0, 1])).toBeUndefined()) - ) + it('returns a falsy value', () => + expect( + languageMode.bufferRangeForScopeAtPosition('.bogus', [0, 1]) + ).toBeUndefined())) describe('when the selector matches a single token at the position', () => { it('returns the range covered by the token', () => { - expect(languageMode.bufferRangeForScopeAtPosition('.storage.type.var.js', [0, 1])).toEqual([[0, 0], [0, 3]]) - expect(languageMode.bufferRangeForScopeAtPosition('.storage.type.var.js', [0, 3])).toEqual([[0, 0], [0, 3]]) + expect( + languageMode.bufferRangeForScopeAtPosition('.storage.type.var.js', [ + 0, + 1 + ]) + ).toEqual([[0, 0], [0, 3]]) + expect( + languageMode.bufferRangeForScopeAtPosition('.storage.type.var.js', [ + 0, + 3 + ]) + ).toEqual([[0, 0], [0, 3]]) }) }) describe('when the selector matches a run of multiple tokens at the position', () => { it('returns the range covered by all contiguous tokens (within a single line)', () => { - expect(languageMode.bufferRangeForScopeAtPosition('.function', [1, 18])).toEqual([[1, 6], [1, 28]]) + expect( + languageMode.bufferRangeForScopeAtPosition('.function', [1, 18]) + ).toEqual([[1, 6], [1, 28]]) }) }) }) @@ -430,7 +624,7 @@ describe('TextMateLanguageMode', () => { it("returns the tokenized line for a row, or a placeholder line if it hasn't been tokenized yet", () => { buffer = atom.project.bufferForPathSync('sample.js') const grammar = atom.grammars.grammarForScopeName('source.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar}) + languageMode = new TextMateLanguageMode({ buffer, config, grammar }) const line0 = buffer.lineForRow(0) const jsScopeStartId = grammar.startIdForScope(grammar.scopeName) @@ -438,93 +632,220 @@ describe('TextMateLanguageMode', () => { languageMode.startTokenizing() expect(languageMode.tokenizedLines[0]).toBeUndefined() expect(languageMode.tokenizedLineForRow(0).text).toBe(line0) - expect(languageMode.tokenizedLineForRow(0).tags).toEqual([jsScopeStartId, line0.length, jsScopeEndId]) + expect(languageMode.tokenizedLineForRow(0).tags).toEqual([ + jsScopeStartId, + line0.length, + jsScopeEndId + ]) advanceClock(1) expect(languageMode.tokenizedLines[0]).not.toBeUndefined() expect(languageMode.tokenizedLineForRow(0).text).toBe(line0) - expect(languageMode.tokenizedLineForRow(0).tags).not.toEqual([jsScopeStartId, line0.length, jsScopeEndId]) + expect(languageMode.tokenizedLineForRow(0).tags).not.toEqual([ + jsScopeStartId, + line0.length, + jsScopeEndId + ]) }) it('returns undefined if the requested row is outside the buffer range', () => { buffer = atom.project.bufferForPathSync('sample.js') const grammar = atom.grammars.grammarForScopeName('source.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar}) + languageMode = new TextMateLanguageMode({ buffer, config, grammar }) fullyTokenize(languageMode) expect(languageMode.tokenizedLineForRow(999)).toBeUndefined() }) }) describe('.buildHighlightIterator', () => { - const {TextMateHighlightIterator} = TextMateLanguageMode + const { TextMateHighlightIterator } = TextMateLanguageMode it('iterates over the syntactic scope boundaries', () => { - buffer = new TextBuffer({text: 'var foo = 1 /*\nhello*/var bar = 2\n'}) - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + buffer = new TextBuffer({ text: 'var foo = 1 /*\nhello*/var bar = 2\n' }) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) fullyTokenize(languageMode) const iterator = languageMode.buildHighlightIterator() iterator.seek(Point(0, 0)) const expectedBoundaries = [ - {position: Point(0, 0), closeTags: [], openTags: ['syntax--source syntax--js', 'syntax--storage syntax--type syntax--var syntax--js']}, - {position: Point(0, 3), closeTags: ['syntax--storage syntax--type syntax--var syntax--js'], openTags: []}, - {position: Point(0, 8), closeTags: [], openTags: ['syntax--keyword syntax--operator syntax--assignment syntax--js']}, - {position: Point(0, 9), closeTags: ['syntax--keyword syntax--operator syntax--assignment syntax--js'], openTags: []}, - {position: Point(0, 10), closeTags: [], openTags: ['syntax--constant syntax--numeric syntax--decimal syntax--js']}, - {position: Point(0, 11), closeTags: ['syntax--constant syntax--numeric syntax--decimal syntax--js'], openTags: []}, - {position: Point(0, 12), closeTags: [], openTags: ['syntax--comment syntax--block syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--begin syntax--js']}, - {position: Point(0, 14), closeTags: ['syntax--punctuation syntax--definition syntax--comment syntax--begin syntax--js'], openTags: []}, - {position: Point(1, 5), closeTags: [], openTags: ['syntax--punctuation syntax--definition syntax--comment syntax--end syntax--js']}, - {position: Point(1, 7), closeTags: ['syntax--punctuation syntax--definition syntax--comment syntax--end syntax--js', 'syntax--comment syntax--block syntax--js'], openTags: ['syntax--storage syntax--type syntax--var syntax--js']}, - {position: Point(1, 10), closeTags: ['syntax--storage syntax--type syntax--var syntax--js'], openTags: []}, - {position: Point(1, 15), closeTags: [], openTags: ['syntax--keyword syntax--operator syntax--assignment syntax--js']}, - {position: Point(1, 16), closeTags: ['syntax--keyword syntax--operator syntax--assignment syntax--js'], openTags: []}, - {position: Point(1, 17), closeTags: [], openTags: ['syntax--constant syntax--numeric syntax--decimal syntax--js']}, - {position: Point(1, 18), closeTags: ['syntax--constant syntax--numeric syntax--decimal syntax--js'], openTags: []} + { + position: Point(0, 0), + closeTags: [], + openTags: [ + 'syntax--source syntax--js', + 'syntax--storage syntax--type syntax--var syntax--js' + ] + }, + { + position: Point(0, 3), + closeTags: ['syntax--storage syntax--type syntax--var syntax--js'], + openTags: [] + }, + { + position: Point(0, 8), + closeTags: [], + openTags: [ + 'syntax--keyword syntax--operator syntax--assignment syntax--js' + ] + }, + { + position: Point(0, 9), + closeTags: [ + 'syntax--keyword syntax--operator syntax--assignment syntax--js' + ], + openTags: [] + }, + { + position: Point(0, 10), + closeTags: [], + openTags: [ + 'syntax--constant syntax--numeric syntax--decimal syntax--js' + ] + }, + { + position: Point(0, 11), + closeTags: [ + 'syntax--constant syntax--numeric syntax--decimal syntax--js' + ], + openTags: [] + }, + { + position: Point(0, 12), + closeTags: [], + openTags: [ + 'syntax--comment syntax--block syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--begin syntax--js' + ] + }, + { + position: Point(0, 14), + closeTags: [ + 'syntax--punctuation syntax--definition syntax--comment syntax--begin syntax--js' + ], + openTags: [] + }, + { + position: Point(1, 5), + closeTags: [], + openTags: [ + 'syntax--punctuation syntax--definition syntax--comment syntax--end syntax--js' + ] + }, + { + position: Point(1, 7), + closeTags: [ + 'syntax--punctuation syntax--definition syntax--comment syntax--end syntax--js', + 'syntax--comment syntax--block syntax--js' + ], + openTags: ['syntax--storage syntax--type syntax--var syntax--js'] + }, + { + position: Point(1, 10), + closeTags: ['syntax--storage syntax--type syntax--var syntax--js'], + openTags: [] + }, + { + position: Point(1, 15), + closeTags: [], + openTags: [ + 'syntax--keyword syntax--operator syntax--assignment syntax--js' + ] + }, + { + position: Point(1, 16), + closeTags: [ + 'syntax--keyword syntax--operator syntax--assignment syntax--js' + ], + openTags: [] + }, + { + position: Point(1, 17), + closeTags: [], + openTags: [ + 'syntax--constant syntax--numeric syntax--decimal syntax--js' + ] + }, + { + position: Point(1, 18), + closeTags: [ + 'syntax--constant syntax--numeric syntax--decimal syntax--js' + ], + openTags: [] + } ] while (true) { const boundary = { position: iterator.getPosition(), - closeTags: iterator.getCloseScopeIds().map(scopeId => languageMode.classNameForScopeId(scopeId)), - openTags: iterator.getOpenScopeIds().map(scopeId => languageMode.classNameForScopeId(scopeId)) + closeTags: iterator + .getCloseScopeIds() + .map(scopeId => languageMode.classNameForScopeId(scopeId)), + openTags: iterator + .getOpenScopeIds() + .map(scopeId => languageMode.classNameForScopeId(scopeId)) } expect(boundary).toEqual(expectedBoundaries.shift()) - if (!iterator.moveToSuccessor()) { break } + if (!iterator.moveToSuccessor()) { + break + } } - expect(iterator.seek(Point(0, 1)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ + expect( + iterator + .seek(Point(0, 1)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual([ 'syntax--source syntax--js', 'syntax--storage syntax--type syntax--var syntax--js' ]) expect(iterator.getPosition()).toEqual(Point(0, 3)) - expect(iterator.seek(Point(0, 8)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ - 'syntax--source syntax--js' - ]) + expect( + iterator + .seek(Point(0, 8)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual(['syntax--source syntax--js']) expect(iterator.getPosition()).toEqual(Point(0, 8)) - expect(iterator.seek(Point(1, 0)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ + expect( + iterator + .seek(Point(1, 0)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual([ 'syntax--source syntax--js', 'syntax--comment syntax--block syntax--js' ]) expect(iterator.getPosition()).toEqual(Point(1, 0)) - expect(iterator.seek(Point(1, 18)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ + expect( + iterator + .seek(Point(1, 18)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual([ 'syntax--source syntax--js', 'syntax--constant syntax--numeric syntax--decimal syntax--js' ]) expect(iterator.getPosition()).toEqual(Point(1, 18)) - expect(iterator.seek(Point(2, 0)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ - 'syntax--source syntax--js' - ]) + expect( + iterator + .seek(Point(2, 0)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual(['syntax--source syntax--js']) iterator.moveToSuccessor() }) // ensure we don't infinitely loop (regression test) it('does not report columns beyond the length of the line', async () => { await atom.packages.activatePackage('language-coffee-script') - buffer = new TextBuffer({text: '# hello\n# world'}) - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.coffee')}) + buffer = new TextBuffer({ text: '# hello\n# world' }) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.coffee') + }) fullyTokenize(languageMode) const iterator = languageMode.buildHighlightIterator() @@ -545,24 +866,32 @@ describe('TextMateLanguageMode', () => { it('correctly terminates scopes at the beginning of the line (regression)', () => { const grammar = atom.grammars.createGrammar('test', { - 'scopeName': 'text.broken', - 'name': 'Broken grammar', - 'patterns': [ - {'begin': 'start', 'end': '(?=end)', 'name': 'blue.broken'}, - {'match': '.', 'name': 'yellow.broken'} + scopeName: 'text.broken', + name: 'Broken grammar', + patterns: [ + { begin: 'start', end: '(?=end)', name: 'blue.broken' }, + { match: '.', name: 'yellow.broken' } ] }) - buffer = new TextBuffer({text: 'start x\nend x\nx'}) - languageMode = new TextMateLanguageMode({buffer, config, grammar}) + buffer = new TextBuffer({ text: 'start x\nend x\nx' }) + languageMode = new TextMateLanguageMode({ buffer, config, grammar }) fullyTokenize(languageMode) const iterator = languageMode.buildHighlightIterator() iterator.seek(Point(1, 0)) expect(iterator.getPosition()).toEqual([1, 0]) - expect(iterator.getCloseScopeIds().map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual(['syntax--blue syntax--broken']) - expect(iterator.getOpenScopeIds().map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual(['syntax--yellow syntax--broken']) + expect( + iterator + .getCloseScopeIds() + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual(['syntax--blue syntax--broken']) + expect( + iterator + .getOpenScopeIds() + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual(['syntax--yellow syntax--broken']) }) describe('TextMateHighlightIterator.seek(position)', function () { @@ -675,7 +1004,7 @@ describe('TextMateLanguageMode', () => { describe('javascript', () => { beforeEach(async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) await atom.packages.activatePackage('language-javascript') }) @@ -690,7 +1019,7 @@ describe('TextMateLanguageMode', () => { }) it('does not take invisibles into account', () => { - editor.update({showInvisibles: true}) + editor.update({ showInvisibles: true }) expect(editor.suggestedIndentForBufferRow(0)).toBe(0) expect(editor.suggestedIndentForBufferRow(1)).toBe(1) expect(editor.suggestedIndentForBufferRow(2)).toBe(2) @@ -703,7 +1032,7 @@ describe('TextMateLanguageMode', () => { describe('css', () => { beforeEach(async () => { - editor = await atom.workspace.open('css.css', {autoIndent: true}) + editor = await atom.workspace.open('css.css', { autoIndent: true }) await atom.packages.activatePackage('language-source') await atom.packages.activatePackage('language-css') }) @@ -720,7 +1049,11 @@ describe('TextMateLanguageMode', () => { buffer = atom.project.bufferForPathSync('sample.js') buffer.insert([10, 0], ' // multi-line\n // comment\n // block\n') buffer.insert([0, 0], '// multi-line\n// comment\n// block\n') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) buffer.setLanguageMode(languageMode) fullyTokenize(languageMode) }) @@ -820,7 +1153,7 @@ describe('TextMateLanguageMode', () => { describe('.getFoldableRangesAtIndentLevel', () => { it('returns the ranges that can be folded at the given indent level', () => { - buffer = new TextBuffer(dedent ` + buffer = new TextBuffer(dedent` if (a) { b(); if (c) { @@ -838,9 +1171,10 @@ describe('TextMateLanguageMode', () => { } `) - languageMode = new TextMateLanguageMode({buffer, config}) + languageMode = new TextMateLanguageMode({ buffer, config }) - expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(0, 2))).toBe(dedent ` + expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(0, 2))) + .toBe(dedent` if (a) {⋯ } i() @@ -848,7 +1182,8 @@ describe('TextMateLanguageMode', () => { } `) - expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(1, 2))).toBe(dedent ` + expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(1, 2))) + .toBe(dedent` if (a) { b(); if (c) {⋯ @@ -861,7 +1196,8 @@ describe('TextMateLanguageMode', () => { } `) - expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(2, 2))).toBe(dedent ` + expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(2, 2))) + .toBe(dedent` if (a) { b(); if (c) { @@ -896,7 +1232,7 @@ describe('TextMateLanguageMode', () => { describe('.getFoldableRanges', () => { it('returns the ranges that can be folded', () => { - buffer = new TextBuffer(dedent ` + buffer = new TextBuffer(dedent` if (a) { b(); if (c) { @@ -914,18 +1250,24 @@ describe('TextMateLanguageMode', () => { } `) - languageMode = new TextMateLanguageMode({buffer, config}) + languageMode = new TextMateLanguageMode({ buffer, config }) - expect(languageMode.getFoldableRanges(2).map(r => r.toString())).toEqual([ - ...languageMode.getFoldableRangesAtIndentLevel(0, 2), - ...languageMode.getFoldableRangesAtIndentLevel(1, 2), - ...languageMode.getFoldableRangesAtIndentLevel(2, 2), - ].sort((a, b) => (a.start.row - b.start.row) || (a.end.row - b.end.row)).map(r => r.toString())) + expect(languageMode.getFoldableRanges(2).map(r => r.toString())).toEqual( + [ + ...languageMode.getFoldableRangesAtIndentLevel(0, 2), + ...languageMode.getFoldableRangesAtIndentLevel(1, 2), + ...languageMode.getFoldableRangesAtIndentLevel(2, 2) + ] + .sort((a, b) => a.start.row - b.start.row || a.end.row - b.end.row) + .map(r => r.toString()) + ) }) it('works with multi-line comments', async () => { await atom.packages.activatePackage('language-javascript') - editor = await atom.workspace.open('sample-with-comments.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-comments.js', { + autoIndent: false + }) fullyTokenize(editor.getBuffer().getLanguageMode()) editor.foldAll() @@ -944,7 +1286,7 @@ describe('TextMateLanguageMode', () => { describe('.getFoldableRangeContainingPoint', () => { it('returns the range for the smallest fold that contains the given range', () => { - buffer = new TextBuffer(dedent ` + buffer = new TextBuffer(dedent` if (a) { b(); if (c) { @@ -962,12 +1304,14 @@ describe('TextMateLanguageMode', () => { } `) - languageMode = new TextMateLanguageMode({buffer, config}) + languageMode = new TextMateLanguageMode({ buffer, config }) - expect(languageMode.getFoldableRangeContainingPoint(Point(0, 5), 2)).toBeNull() + expect( + languageMode.getFoldableRangeContainingPoint(Point(0, 5), 2) + ).toBeNull() let range = languageMode.getFoldableRangeContainingPoint(Point(0, 10), 2) - expect(simulateFold([range])).toBe(dedent ` + expect(simulateFold([range])).toBe(dedent` if (a) {⋯ } i() @@ -977,7 +1321,7 @@ describe('TextMateLanguageMode', () => { `) range = languageMode.getFoldableRangeContainingPoint(Point(7, 0), 2) - expect(simulateFold([range])).toBe(dedent ` + expect(simulateFold([range])).toBe(dedent` if (a) { b(); if (c) {⋯ @@ -990,8 +1334,11 @@ describe('TextMateLanguageMode', () => { } `) - range = languageMode.getFoldableRangeContainingPoint(Point(1, Infinity), 2) - expect(simulateFold([range])).toBe(dedent ` + range = languageMode.getFoldableRangeContainingPoint( + Point(1, Infinity), + 2 + ) + expect(simulateFold([range])).toBe(dedent` if (a) {⋯ } i() @@ -1001,7 +1348,7 @@ describe('TextMateLanguageMode', () => { `) range = languageMode.getFoldableRangeContainingPoint(Point(2, 20), 2) - expect(simulateFold([range])).toBe(dedent ` + expect(simulateFold([range])).toBe(dedent` if (a) { b(); if (c) {⋯ @@ -1021,10 +1368,18 @@ describe('TextMateLanguageMode', () => { buffer = editor.buffer languageMode = editor.languageMode - expect(languageMode.getFoldableRangeContainingPoint(Point(0, Infinity), 2)).toEqual([[0, Infinity], [20, Infinity]]) - expect(languageMode.getFoldableRangeContainingPoint(Point(1, Infinity), 2)).toEqual([[1, Infinity], [17, Infinity]]) - expect(languageMode.getFoldableRangeContainingPoint(Point(2, Infinity), 2)).toEqual([[1, Infinity], [17, Infinity]]) - expect(languageMode.getFoldableRangeContainingPoint(Point(19, Infinity), 2)).toEqual([[19, Infinity], [20, Infinity]]) + expect( + languageMode.getFoldableRangeContainingPoint(Point(0, Infinity), 2) + ).toEqual([[0, Infinity], [20, Infinity]]) + expect( + languageMode.getFoldableRangeContainingPoint(Point(1, Infinity), 2) + ).toEqual([[1, Infinity], [17, Infinity]]) + expect( + languageMode.getFoldableRangeContainingPoint(Point(2, Infinity), 2) + ).toEqual([[1, Infinity], [17, Infinity]]) + expect( + languageMode.getFoldableRangeContainingPoint(Point(19, Infinity), 2) + ).toEqual([[19, Infinity], [20, Infinity]]) }) it('works for javascript', async () => { @@ -1033,16 +1388,39 @@ describe('TextMateLanguageMode', () => { buffer = editor.buffer languageMode = editor.languageMode - expect(editor.languageMode.getFoldableRangeContainingPoint(Point(0, Infinity), 2)).toEqual([[0, Infinity], [12, Infinity]]) - expect(editor.languageMode.getFoldableRangeContainingPoint(Point(1, Infinity), 2)).toEqual([[1, Infinity], [9, Infinity]]) - expect(editor.languageMode.getFoldableRangeContainingPoint(Point(2, Infinity), 2)).toEqual([[1, Infinity], [9, Infinity]]) - expect(editor.languageMode.getFoldableRangeContainingPoint(Point(4, Infinity), 2)).toEqual([[4, Infinity], [7, Infinity]]) + expect( + editor.languageMode.getFoldableRangeContainingPoint( + Point(0, Infinity), + 2 + ) + ).toEqual([[0, Infinity], [12, Infinity]]) + expect( + editor.languageMode.getFoldableRangeContainingPoint( + Point(1, Infinity), + 2 + ) + ).toEqual([[1, Infinity], [9, Infinity]]) + expect( + editor.languageMode.getFoldableRangeContainingPoint( + Point(2, Infinity), + 2 + ) + ).toEqual([[1, Infinity], [9, Infinity]]) + expect( + editor.languageMode.getFoldableRangeContainingPoint( + Point(4, Infinity), + 2 + ) + ).toEqual([[4, Infinity], [7, Infinity]]) }) it('searches upward and downward for surrounding comment lines and folds them as a single fold', async () => { await atom.packages.activatePackage('language-javascript') editor = await atom.workspace.open('sample-with-comments.js') - editor.buffer.insert([1, 0], ' //this is a comment\n // and\n //more docs\n\n//second comment') + editor.buffer.insert( + [1, 0], + ' //this is a comment\n // and\n //more docs\n\n//second comment' + ) fullyTokenize(editor.getBuffer().getLanguageMode()) editor.foldBufferRow(1) const [fold] = editor.unfoldAll() @@ -1053,26 +1431,28 @@ describe('TextMateLanguageMode', () => { describe('TokenIterator', () => it('correctly terminates scopes at the beginning of the line (regression)', () => { const grammar = atom.grammars.createGrammar('test', { - 'scopeName': 'text.broken', - 'name': 'Broken grammar', - 'patterns': [ + scopeName: 'text.broken', + name: 'Broken grammar', + patterns: [ { - 'begin': 'start', - 'end': '(?=end)', - 'name': 'blue.broken' + begin: 'start', + end: '(?=end)', + name: 'blue.broken' }, { - 'match': '.', - 'name': 'yellow.broken' + match: '.', + name: 'yellow.broken' } ] }) - const buffer = new TextBuffer({text: dedent` + const buffer = new TextBuffer({ + text: dedent` start x end x x - `}) + ` + }) const languageMode = new TextMateLanguageMode({ buffer, @@ -1085,14 +1465,18 @@ describe('TextMateLanguageMode', () => { fullyTokenize(languageMode) - const tokenIterator = languageMode.tokenizedLineForRow(1).getTokenIterator() + const tokenIterator = languageMode + .tokenizedLineForRow(1) + .getTokenIterator() tokenIterator.next() expect(tokenIterator.getBufferStart()).toBe(0) expect(tokenIterator.getScopeEnds()).toEqual([]) - expect(tokenIterator.getScopeStarts()).toEqual(['text.broken', 'yellow.broken']) - }) - ) + expect(tokenIterator.getScopeStarts()).toEqual([ + 'text.broken', + 'yellow.broken' + ]) + })) function simulateFold (ranges) { buffer.transact(() => { diff --git a/spec/text-utils-spec.js b/spec/text-utils-spec.js index 3a4b29866..ca0e2a6d7 100644 --- a/spec/text-utils-spec.js +++ b/spec/text-utils-spec.js @@ -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) - }) - ) + })) }) diff --git a/spec/theme-manager-spec.js b/spec/theme-manager-spec.js index 9d1d3a3cc..2de214921 100644 --- a/spec/theme-manager-spec.js +++ b/spec/theme-manager-spec.js @@ -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,27 @@ 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 +532,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 +582,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 +600,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 +618,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()) }) diff --git a/spec/title-bar-spec.js b/spec/title-bar-spec.js index b219a5819..c5d98ed03 100644 --- a/spec/title-bar-spec.js +++ b/spec/title-bar-spec.js @@ -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 + } } } diff --git a/spec/tooltip-manager-spec.js b/spec/tooltip-manager-spec.js index e6ca01de2..183439a3c 100644 --- a/spec/tooltip-manager-spec.js +++ b/spec/tooltip-manager-spec.js @@ -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 })) } diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index 7b8344d9c..e4b41b994 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1,22 +1,39 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const fs = require('fs') const path = require('path') const dedent = require('dedent') const TextBuffer = require('text-buffer') -const {Point} = TextBuffer +const { Point } = TextBuffer const TextEditor = require('../src/text-editor') const TreeSitterGrammar = require('../src/tree-sitter-grammar') const TreeSitterLanguageMode = require('../src/tree-sitter-language-mode') const Random = require('../script/node_modules/random-seed') -const {getRandomBufferRange, buildRandomLines} = require('./helpers/random') +const { getRandomBufferRange, buildRandomLines } = require('./helpers/random') const cGrammarPath = require.resolve('language-c/grammars/tree-sitter-c.cson') -const pythonGrammarPath = require.resolve('language-python/grammars/tree-sitter-python.cson') -const jsGrammarPath = require.resolve('language-javascript/grammars/tree-sitter-javascript.cson') -const htmlGrammarPath = require.resolve('language-html/grammars/tree-sitter-html.cson') -const ejsGrammarPath = require.resolve('language-html/grammars/tree-sitter-ejs.cson') -const rubyGrammarPath = require.resolve('language-ruby/grammars/tree-sitter-ruby.cson') +const pythonGrammarPath = require.resolve( + 'language-python/grammars/tree-sitter-python.cson' +) +const jsGrammarPath = require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' +) +const htmlGrammarPath = require.resolve( + 'language-html/grammars/tree-sitter-html.cson' +) +const ejsGrammarPath = require.resolve( + 'language-html/grammars/tree-sitter-ejs.cson' +) +const rubyGrammarPath = require.resolve( + 'language-ruby/grammars/tree-sitter-ruby.cson' +) describe('TreeSitterLanguageMode', () => { let editor, buffer @@ -24,7 +41,7 @@ describe('TreeSitterLanguageMode', () => { beforeEach(async () => { editor = await atom.workspace.open('') buffer = editor.getBuffer() - editor.displayLayer.reset({foldCharacter: '…'}) + editor.displayLayer.reset({ foldCharacter: '…' }) }) describe('highlighting', () => { @@ -32,82 +49,85 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'program': 'source', + program: 'source', 'call_expression > identifier': 'function', - 'property_identifier': 'property', + property_identifier: 'property', 'call_expression > member_expression > property_identifier': 'method' } }) buffer.setText('aa.bbb = cc(d.eee());') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) - expectTokensToEqual(editor, [[ - {text: 'aa.', scopes: ['source']}, - {text: 'bbb', scopes: ['source', 'property']}, - {text: ' = ', scopes: ['source']}, - {text: 'cc', scopes: ['source', 'function']}, - {text: '(d.', scopes: ['source']}, - {text: 'eee', scopes: ['source', 'method']}, - {text: '());', scopes: ['source']} - ]]) + expectTokensToEqual(editor, [ + [ + { text: 'aa.', scopes: ['source'] }, + { text: 'bbb', scopes: ['source', 'property'] }, + { text: ' = ', scopes: ['source'] }, + { text: 'cc', scopes: ['source', 'function'] }, + { text: '(d.', scopes: ['source'] }, + { text: 'eee', scopes: ['source', 'method'] }, + { text: '());', scopes: ['source'] } + ] + ]) }) it('can start or end multiple scopes at the same position', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'program': 'source', - 'call_expression': 'call', - 'member_expression': 'member', - 'identifier': 'variable', + program: 'source', + call_expression: 'call', + member_expression: 'member', + identifier: 'variable', '"("': 'open-paren', - '")"': 'close-paren', + '")"': 'close-paren' } }) buffer.setText('a = bb.ccc();') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) - expectTokensToEqual(editor, [[ - {text: 'a', scopes: ['source', 'variable']}, - {text: ' = ', scopes: ['source']}, - {text: 'bb', scopes: ['source', 'call', 'member', 'variable']}, - {text: '.ccc', scopes: ['source', 'call', 'member']}, - {text: '(', scopes: ['source', 'call', 'open-paren']}, - {text: ')', scopes: ['source', 'call', 'close-paren']}, - {text: ';', scopes: ['source']} - ]]) + expectTokensToEqual(editor, [ + [ + { text: 'a', scopes: ['source', 'variable'] }, + { text: ' = ', scopes: ['source'] }, + { text: 'bb', scopes: ['source', 'call', 'member', 'variable'] }, + { text: '.ccc', scopes: ['source', 'call', 'member'] }, + { text: '(', scopes: ['source', 'call', 'open-paren'] }, + { text: ')', scopes: ['source', 'call', 'close-paren'] }, + { text: ';', scopes: ['source'] } + ] + ]) }) it('can resume highlighting on a line that starts with whitespace', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'call_expression > member_expression > property_identifier': 'function', - 'property_identifier': 'member', - 'identifier': 'variable' + 'call_expression > member_expression > property_identifier': + 'function', + property_identifier: 'member', + identifier: 'variable' } }) buffer.setText('a\n .b();') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ + [{ text: 'a', scopes: ['variable'] }], [ - {text: 'a', scopes: ['variable']}, - ], - [ - {text: ' ', scopes: ['leading-whitespace']}, - {text: '.', scopes: []}, - {text: 'b', scopes: ['function']}, - {text: '();', scopes: []} + { text: ' ', scopes: ['leading-whitespace'] }, + { text: '.', scopes: [] }, + { text: 'b', scopes: ['function'] }, + { text: '();', scopes: [] } ] ]) }) @@ -116,77 +136,74 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, cGrammarPath, { parser: 'tree-sitter-c', scopes: { - 'primitive_type': 'type', - 'identifier': 'variable', + primitive_type: 'type', + identifier: 'variable' } }) - buffer.setText('int main() {\n int a\n int b;\n}'); + buffer.setText('int main() {\n int a\n int b;\n}') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect( - languageMode.tree.rootNode.descendantForPosition(Point(1, 2), Point(1, 6)).toString() + languageMode.tree.rootNode + .descendantForPosition(Point(1, 2), Point(1, 6)) + .toString() ).toBe('(declaration (primitive_type) (identifier) (MISSING))') expectTokensToEqual(editor, [ [ - {text: 'int', scopes: ['type']}, - {text: ' ', scopes: []}, - {text: 'main', scopes: ['variable']}, - {text: '() {', scopes: []} + { text: 'int', scopes: ['type'] }, + { text: ' ', scopes: [] }, + { text: 'main', scopes: ['variable'] }, + { text: '() {', scopes: [] } ], [ - {text: ' ', scopes: ['leading-whitespace']}, - {text: 'int', scopes: ['type']}, - {text: ' ', scopes: []}, - {text: 'a', scopes: ['variable']} + { text: ' ', scopes: ['leading-whitespace'] }, + { text: 'int', scopes: ['type'] }, + { text: ' ', scopes: [] }, + { text: 'a', scopes: ['variable'] } ], [ - {text: ' ', scopes: ['leading-whitespace']}, - {text: 'int', scopes: ['type']}, - {text: ' ', scopes: []}, - {text: 'b', scopes: ['variable']}, - {text: ';', scopes: []} + { text: ' ', scopes: ['leading-whitespace'] }, + { text: 'int', scopes: ['type'] }, + { text: ' ', scopes: [] }, + { text: 'b', scopes: ['variable'] }, + { text: ';', scopes: [] } ], - [ - {text: '}', scopes: []} - ] + [{ text: '}', scopes: [] }] ]) }) - it('updates lines\' highlighting when they are affected by distant changes', async () => { + it("updates lines' highlighting when they are affected by distant changes", async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { 'call_expression > identifier': 'function', - 'property_identifier': 'member' + property_identifier: 'member' } }) buffer.setText('a(\nb,\nc\n') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) // missing closing paren expectTokensToEqual(editor, [ - [{text: 'a(', scopes: []}], - [{text: 'b,', scopes: []}], - [{text: 'c', scopes: []}], - [{text: '', scopes: []}] + [{ text: 'a(', scopes: [] }], + [{ text: 'b,', scopes: [] }], + [{ text: 'c', scopes: [] }], + [{ text: '', scopes: [] }] ]) buffer.append(')') expectTokensToEqual(editor, [ - [ - {text: 'a', scopes: ['function']}, - {text: '(', scopes: []} - ], - [{text: 'b,', scopes: []}], - [{text: 'c', scopes: []}], - [{text: ')', scopes: []}] + [{ text: 'a', scopes: ['function'] }, { text: '(', scopes: [] }], + [{ text: 'b,', scopes: [] }], + [{ text: 'c', scopes: [] }], + [{ text: ')', scopes: [] }] ]) }) @@ -195,7 +212,7 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', scopes: { 'identifier, call_expression > identifier': [ - {match: '^[A-Z]', scopes: 'constructor'} + { match: '^[A-Z]', scopes: 'constructor' } ], 'call_expression > identifier': 'function' @@ -204,17 +221,17 @@ describe('TreeSitterLanguageMode', () => { buffer.setText(`a(B(new C))`) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'a', scopes: ['function']}, - {text: '(', scopes: []}, - {text: 'B', scopes: ['constructor']}, - {text: '(new ', scopes: []}, - {text: 'C', scopes: ['constructor']}, - {text: '))', scopes: []}, + { text: 'a', scopes: ['function'] }, + { text: '(', scopes: [] }, + { text: 'B', scopes: ['constructor'] }, + { text: '(new ', scopes: [] }, + { text: 'C', scopes: ['constructor'] }, + { text: '))', scopes: [] } ] ]) }) @@ -223,42 +240,38 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'comment': 'comment', - 'string': 'string', - 'property_identifier': 'property', + comment: 'comment', + string: 'string', + property_identifier: 'property' } }) - buffer.setText([ - '// abc', - '', - 'a("b").c' - ].join('\r\n')) + buffer.setText(['// abc', '', 'a("b").c'].join('\r\n')) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ - [{text: '// abc', scopes: ['comment']}], - [{text: '', scopes: []}], + [{ text: '// abc', scopes: ['comment'] }], + [{ text: '', scopes: [] }], [ - {text: 'a(', scopes: []}, - {text: '"b"', scopes: ['string']}, - {text: ').', scopes: []}, - {text: 'c', scopes: ['property']} + { text: 'a(', scopes: [] }, + { text: '"b"', scopes: ['string'] }, + { text: ').', scopes: [] }, + { text: 'c', scopes: ['property'] } ] ]) buffer.insert([2, 0], ' ') expectTokensToEqual(editor, [ - [{text: '// abc', scopes: ['comment']}], - [{text: '', scopes: []}], + [{ text: '// abc', scopes: ['comment'] }], + [{ text: '', scopes: [] }], [ - {text: ' ', scopes: ['leading-whitespace']}, - {text: 'a(', scopes: []}, - {text: '"b"', scopes: ['string']}, - {text: ').', scopes: []}, - {text: 'c', scopes: ['property']} + { text: ' ', scopes: ['leading-whitespace'] }, + { text: 'a(', scopes: [] }, + { text: '"b"', scopes: ['string'] }, + { text: ').', scopes: [] }, + { text: 'c', scopes: ['property'] } ] ]) }) @@ -267,35 +280,32 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'template_string': 'string', + template_string: 'string', '"${"': 'interpolation', '"}"': 'interpolation' } - }); + }) buffer.setText('`\na${1}\nb${2}\n`;') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ + [{ text: '`', scopes: ['string'] }], [ - {text: '`', scopes: ['string']} - ], [ - {text: 'a', scopes: ['string']}, - {text: '${', scopes: ['string', 'interpolation']}, - {text: '1', scopes: ['string']}, - {text: '}', scopes: ['string', 'interpolation']} - ], [ - {text: 'b', scopes: ['string']}, - {text: '${', scopes: ['string', 'interpolation']}, - {text: '2', scopes: ['string']}, - {text: '}', scopes: ['string', 'interpolation']} + { text: 'a', scopes: ['string'] }, + { text: '${', scopes: ['string', 'interpolation'] }, + { text: '1', scopes: ['string'] }, + { text: '}', scopes: ['string', 'interpolation'] } ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []} - ] + { text: 'b', scopes: ['string'] }, + { text: '${', scopes: ['string', 'interpolation'] }, + { text: '2', scopes: ['string'] }, + { text: '}', scopes: ['string', 'interpolation'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) }) @@ -303,12 +313,12 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'comment': 'comment', - 'call_expression > identifier': 'function', + comment: 'comment', + 'call_expression > identifier': 'function' } }) - buffer.setText(dedent ` + buffer.setText(dedent` /* * Hello */ @@ -316,24 +326,19 @@ describe('TreeSitterLanguageMode', () => { hello(); `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) editor.foldBufferRange([[0, 2], [2, 0]]) expectTokensToEqual(editor, [ [ - {text: '/*', scopes: ['comment']}, - {text: '…', scopes: ['fold-marker']}, - {text: ' */', scopes: ['comment']} + { text: '/*', scopes: ['comment'] }, + { text: '…', scopes: ['fold-marker'] }, + { text: ' */', scopes: ['comment'] } ], - [ - {text: '', scopes: []} - ], - [ - {text: 'hello', scopes: ['function']}, - {text: '();', scopes: []}, - ] + [{ text: '', scopes: [] }], + [{ text: 'hello', scopes: ['function'] }, { text: '();', scopes: [] }] ]) }) @@ -341,30 +346,30 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'identifier': [ - {match: '^(exports|document|window|global)$', scopes: 'global'}, - {match: '^[A-Z_]+$', scopes: 'constant'}, - {match: '^[A-Z]', scopes: 'constructor'}, + identifier: [ + { match: '^(exports|document|window|global)$', scopes: 'global' }, + { match: '^[A-Z_]+$', scopes: 'constant' }, + { match: '^[A-Z]', scopes: 'constructor' }, 'variable' - ], + ] } }) buffer.setText(`exports.object = Class(SOME_CONSTANT, x)`) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'exports', scopes: ['global']}, - {text: '.object = ', scopes: []}, - {text: 'Class', scopes: ['constructor']}, - {text: '(', scopes: []}, - {text: 'SOME_CONSTANT', scopes: ['constant']}, - {text: ', ', scopes: []}, - {text: 'x', scopes: ['variable']}, - {text: ')', scopes: []}, + { text: 'exports', scopes: ['global'] }, + { text: '.object = ', scopes: [] }, + { text: 'Class', scopes: ['constructor'] }, + { text: '(', scopes: [] }, + { text: 'SOME_CONSTANT', scopes: ['constant'] }, + { text: ', ', scopes: [] }, + { text: 'x', scopes: ['variable'] }, + { text: ')', scopes: [] } ] ]) }) @@ -373,10 +378,10 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, rubyGrammarPath, { parser: 'tree-sitter-ruby', scopes: { - 'bare_string': 'string', - 'interpolation': 'embedded', + bare_string: 'string', + interpolation: 'embedded', '"#{"': 'punctuation', - '"}"': 'punctuation', + '"}"': 'punctuation' } }) @@ -384,18 +389,18 @@ describe('TreeSitterLanguageMode', () => { // starts later and ends earlier than the bare string. buffer.setText('a = %W( bc#{d}ef )') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'a = %W( ', scopes: []}, - {text: 'bc', scopes: ['string']}, - {text: '#{', scopes: ['string', 'embedded', 'punctuation']}, - {text: 'd', scopes: ['string', 'embedded']}, - {text: '}', scopes: ['string', 'embedded', 'punctuation']}, - {text: 'ef', scopes: ['string']}, - {text: ' )', scopes: []}, + { text: 'a = %W( ', scopes: [] }, + { text: 'bc', scopes: ['string'] }, + { text: '#{', scopes: ['string', 'embedded', 'punctuation'] }, + { text: 'd', scopes: ['string', 'embedded'] }, + { text: '}', scopes: ['string', 'embedded', 'punctuation'] }, + { text: 'ef', scopes: ['string'] }, + { text: ' )', scopes: [] } ] ]) }) @@ -405,59 +410,57 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'identifier': 'variable', + identifier: 'variable', 'call_expression > identifier': 'function', 'new_expression > identifier': 'constructor' } }) - buffer.setText('abc;'); + buffer.setText('abc;') - const languageMode = new TreeSitterLanguageMode({buffer, grammar, syncOperationLimit: 0}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar, + syncOperationLimit: 0 + }) buffer.setLanguageMode(languageMode) await nextHighlightingUpdate(languageMode) await new Promise(process.nextTick) expectTokensToEqual(editor, [ - [ - {text: 'abc', scopes: ['variable']}, - {text: ';', scopes: []} - ], + [{ text: 'abc', scopes: ['variable'] }, { text: ';', scopes: [] }] ]) - buffer.setTextInRange([[0, 3], [0, 3]], '()'); + buffer.setTextInRange([[0, 3], [0, 3]], '()') expectTokensToEqual(editor, [ - [ - {text: 'abc()', scopes: ['variable']}, - {text: ';', scopes: []} - ], + [{ text: 'abc()', scopes: ['variable'] }, { text: ';', scopes: [] }] ]) - buffer.setTextInRange([[0, 0], [0, 0]], 'new '); + buffer.setTextInRange([[0, 0], [0, 0]], 'new ') expectTokensToEqual(editor, [ [ - {text: 'new ', scopes: []}, - {text: 'abc()', scopes: ['variable']}, - {text: ';', scopes: []} - ], + { text: 'new ', scopes: [] }, + { text: 'abc()', scopes: ['variable'] }, + { text: ';', scopes: [] } + ] ]) await nextHighlightingUpdate(languageMode) expectTokensToEqual(editor, [ [ - {text: 'new ', scopes: []}, - {text: 'abc', scopes: ['function']}, - {text: '();', scopes: []} - ], + { text: 'new ', scopes: [] }, + { text: 'abc', scopes: ['function'] }, + { text: '();', scopes: [] } + ] ]) await nextHighlightingUpdate(languageMode) expectTokensToEqual(editor, [ [ - {text: 'new ', scopes: []}, - {text: 'abc', scopes: ['constructor']}, - {text: '();', scopes: []} - ], + { text: 'new ', scopes: [] }, + { text: 'abc', scopes: ['constructor'] }, + { text: '();', scopes: [] } + ] ]) }) }) @@ -467,42 +470,39 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'property', + property_identifier: 'property', 'call_expression > identifier': 'function', - 'call_expression > member_expression > property_identifier': 'method', + 'call_expression > member_expression > property_identifier': + 'method' } }) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) - buffer.setText('a'); - expectTokensToEqual(editor, [[ - {text: 'a', scopes: []}, - ]]) + buffer.setText('a') + expectTokensToEqual(editor, [[{ text: 'a', scopes: [] }]]) buffer.append('.') - expectTokensToEqual(editor, [[ - {text: 'a.', scopes: []}, - ]]) + expectTokensToEqual(editor, [[{ text: 'a.', scopes: [] }]]) buffer.append('b') - expectTokensToEqual(editor, [[ - {text: 'a.', scopes: []}, - {text: 'b', scopes: ['property']}, - ]]) + expectTokensToEqual(editor, [ + [{ text: 'a.', scopes: [] }, { text: 'b', scopes: ['property'] }] + ]) buffer.append('()') - expectTokensToEqual(editor, [[ - {text: 'a.', scopes: []}, - {text: 'b', scopes: ['method']}, - {text: '()', scopes: []}, - ]]) + expectTokensToEqual(editor, [ + [ + { text: 'a.', scopes: [] }, + { text: 'b', scopes: ['method'] }, + { text: '()', scopes: [] } + ] + ]) buffer.delete([[0, 1], [0, 2]]) - expectTokensToEqual(editor, [[ - {text: 'ab', scopes: ['function']}, - {text: '()', scopes: []}, - ]]) + expectTokensToEqual(editor, [ + [{ text: 'ab', scopes: ['function'] }, { text: '()', scopes: [] }] + ]) }) }) @@ -514,9 +514,9 @@ describe('TreeSitterLanguageMode', () => { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'property', + property_identifier: 'property', 'call_expression > identifier': 'function', - 'template_string': 'string', + template_string: 'string', 'template_substitution > "${"': 'interpolation', 'template_substitution > "}"': 'interpolation' }, @@ -542,32 +542,35 @@ describe('TreeSitterLanguageMode', () => { atom.grammars.addGrammar(htmlGrammar) buffer.setText('node.innerHTML = html `\na ${b}\n`;') - const languageMode = new TreeSitterLanguageMode({buffer, grammar: jsGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: jsGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'node.', scopes: []}, - {text: 'innerHTML', scopes: ['property']}, - {text: ' = ', scopes: []}, - {text: 'html', scopes: ['function']}, - {text: ' ', scopes: []}, - {text: '`', scopes: ['string']}, - {text: '', scopes: ['string', 'html']} - ], [ - {text: 'a ', scopes: ['string', 'html']}, - {text: '${', scopes: ['string', 'html', 'interpolation']}, - {text: 'b', scopes: ['string', 'html']}, - {text: '}', scopes: ['string', 'html', 'interpolation']}, - {text: '<', scopes: ['string', 'html']}, - {text: 'img', scopes: ['string', 'html', 'tag']}, - {text: ' ', scopes: ['string', 'html']}, - {text: 'src', scopes: ['string', 'html', 'attr']}, - {text: '="d">', scopes: ['string', 'html']} - ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []}, + { text: 'node.', scopes: [] }, + { text: 'innerHTML', scopes: ['property'] }, + { text: ' = ', scopes: [] }, + { text: 'html', scopes: ['function'] }, + { text: ' ', scopes: [] }, + { text: '`', scopes: ['string'] }, + { text: '', scopes: ['string', 'html'] } ], + [ + { text: 'a ', scopes: ['string', 'html'] }, + { text: '${', scopes: ['string', 'html', 'interpolation'] }, + { text: 'b', scopes: ['string', 'html'] }, + { text: '}', scopes: ['string', 'html', 'interpolation'] }, + { text: '<', scopes: ['string', 'html'] }, + { text: 'img', scopes: ['string', 'html', 'tag'] }, + { text: ' ', scopes: ['string', 'html'] }, + { text: 'src', scopes: ['string', 'html', 'attr'] }, + { text: '="d">', scopes: ['string', 'html'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) const range = buffer.findSync('html') @@ -576,22 +579,21 @@ describe('TreeSitterLanguageMode', () => { expectTokensToEqual(editor, [ [ - {text: 'node.', scopes: []}, - {text: 'innerHTML', scopes: ['property']}, - {text: ' = ', scopes: []}, - {text: 'xml', scopes: ['function']}, - {text: ' ', scopes: []}, - {text: '`', scopes: ['string']} - ], [ - {text: 'a ', scopes: ['string']}, - {text: '${', scopes: ['string', 'interpolation']}, - {text: 'b', scopes: ['string']}, - {text: '}', scopes: ['string', 'interpolation']}, - {text: '', scopes: ['string']}, - ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []}, + { text: 'node.', scopes: [] }, + { text: 'innerHTML', scopes: ['property'] }, + { text: ' = ', scopes: [] }, + { text: 'xml', scopes: ['function'] }, + { text: ' ', scopes: [] }, + { text: '`', scopes: ['string'] } ], + [ + { text: 'a ', scopes: ['string'] }, + { text: '${', scopes: ['string', 'interpolation'] }, + { text: 'b', scopes: ['string'] }, + { text: '}', scopes: ['string', 'interpolation'] }, + { text: '', scopes: ['string'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) }) @@ -600,33 +602,37 @@ describe('TreeSitterLanguageMode', () => { atom.grammars.addGrammar(htmlGrammar) buffer.setText('\n
\n
') - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: '<', scopes: ['html']}, - {text: 'script', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']}, + { text: '<', scopes: ['html'] }, + { text: 'script', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: 'hello', scopes: ['html', 'function']}, - {text: '();', scopes: ['html']}, + { text: 'hello', scopes: ['html', 'function'] }, + { text: '();', scopes: ['html'] } ], [ - {text: '', scopes: ['html']}, + { text: '', scopes: ['html'] } ], [ - {text: '<', scopes: ['html']}, - {text: 'div', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']}, + { text: '<', scopes: ['html'] }, + { text: 'div', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: '', scopes: ['html']}, + { text: '', scopes: ['html'] } ] ]) }) @@ -635,78 +641,92 @@ describe('TreeSitterLanguageMode', () => { atom.grammars.addGrammar(jsGrammar) buffer.setText('node.innerHTML = html `\na ${b}\n`;') - const languageMode = new TreeSitterLanguageMode({buffer, grammar: jsGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: jsGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'node.', scopes: []}, - {text: 'innerHTML', scopes: ['property']}, - {text: ' = ', scopes: []}, - {text: 'html', scopes: ['function']}, - {text: ' ', scopes: []}, - {text: '`', scopes: ['string']} - ], [ - {text: 'a ', scopes: ['string']}, - {text: '${', scopes: ['string', 'interpolation']}, - {text: 'b', scopes: ['string']}, - {text: '}', scopes: ['string', 'interpolation']}, - {text: '', scopes: ['string']}, - ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []}, + { text: 'node.', scopes: [] }, + { text: 'innerHTML', scopes: ['property'] }, + { text: ' = ', scopes: [] }, + { text: 'html', scopes: ['function'] }, + { text: ' ', scopes: [] }, + { text: '`', scopes: ['string'] } ], + [ + { text: 'a ', scopes: ['string'] }, + { text: '${', scopes: ['string', 'interpolation'] }, + { text: 'b', scopes: ['string'] }, + { text: '}', scopes: ['string', 'interpolation'] }, + { text: '', scopes: ['string'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) atom.grammars.addGrammar(htmlGrammar) await nextHighlightingUpdate(languageMode) expectTokensToEqual(editor, [ [ - {text: 'node.', scopes: []}, - {text: 'innerHTML', scopes: ['property']}, - {text: ' = ', scopes: []}, - {text: 'html', scopes: ['function']}, - {text: ' ', scopes: []}, - {text: '`', scopes: ['string']}, - {text: '', scopes: ['string', 'html']} - ], [ - {text: 'a ', scopes: ['string', 'html']}, - {text: '${', scopes: ['string', 'html', 'interpolation']}, - {text: 'b', scopes: ['string', 'html']}, - {text: '}', scopes: ['string', 'html', 'interpolation']}, - {text: '<', scopes: ['string', 'html']}, - {text: 'img', scopes: ['string', 'html', 'tag']}, - {text: ' ', scopes: ['string', 'html']}, - {text: 'src', scopes: ['string', 'html', 'attr']}, - {text: '="d">', scopes: ['string', 'html']} - ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []}, + { text: 'node.', scopes: [] }, + { text: 'innerHTML', scopes: ['property'] }, + { text: ' = ', scopes: [] }, + { text: 'html', scopes: ['function'] }, + { text: ' ', scopes: [] }, + { text: '`', scopes: ['string'] }, + { text: '', scopes: ['string', 'html'] } ], + [ + { text: 'a ', scopes: ['string', 'html'] }, + { text: '${', scopes: ['string', 'html', 'interpolation'] }, + { text: 'b', scopes: ['string', 'html'] }, + { text: '}', scopes: ['string', 'html', 'interpolation'] }, + { text: '<', scopes: ['string', 'html'] }, + { text: 'img', scopes: ['string', 'html', 'tag'] }, + { text: ' ', scopes: ['string', 'html'] }, + { text: 'src', scopes: ['string', 'html', 'attr'] }, + { text: '="d">', scopes: ['string', 'html'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) }) it('handles injections that intersect', async () => { - const ejsGrammar = new TreeSitterGrammar(atom.grammars, ejsGrammarPath, { - id: 'ejs', - parser: 'tree-sitter-embedded-template', - scopes: { - '"<%="': 'directive', - '"%>"': 'directive', - }, - injectionPoints: [ - { - type: 'template', - language (node) { return 'javascript' }, - content (node) { return node.descendantsOfType('code') } + const ejsGrammar = new TreeSitterGrammar( + atom.grammars, + ejsGrammarPath, + { + id: 'ejs', + parser: 'tree-sitter-embedded-template', + scopes: { + '"<%="': 'directive', + '"%>"': 'directive' }, - { - type: 'template', - language (node) { return 'html' }, - content (node) { return node.descendantsOfType('content') } - } - ] - }) + injectionPoints: [ + { + type: 'template', + language (node) { + return 'javascript' + }, + content (node) { + return node.descendantsOfType('code') + } + }, + { + type: 'template', + language (node) { + return 'html' + }, + content (node) { + return node.descendantsOfType('content') + } + } + ] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -715,41 +735,41 @@ describe('TreeSitterLanguageMode', () => { const languageMode = new TreeSitterLanguageMode({ buffer, grammar: ejsGrammar, - grammars: atom.grammars, + grammars: atom.grammars }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: '<', scopes: ['html']}, - {text: 'body', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']} + { text: '<', scopes: ['html'] }, + { text: 'body', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: '<', scopes: ['html']}, - {text: 'script', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']} + { text: '<', scopes: ['html'] }, + { text: 'script', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: 'b', scopes: ['html', 'function']}, - {text: '(', scopes: ['html']}, - {text: '<%=', scopes: ['html', 'directive']}, - {text: ' c.', scopes: ['html']}, - {text: 'd', scopes: ['html', 'property']}, - {text: ' ', scopes: ['html']}, - {text: '%>', scopes: ['html', 'directive']}, - {text: ')', scopes: ['html']}, + { text: 'b', scopes: ['html', 'function'] }, + { text: '(', scopes: ['html'] }, + { text: '<%=', scopes: ['html', 'directive'] }, + { text: ' c.', scopes: ['html'] }, + { text: 'd', scopes: ['html', 'property'] }, + { text: ' ', scopes: ['html'] }, + { text: '%>', scopes: ['html', 'directive'] }, + { text: ')', scopes: ['html'] } ], [ - {text: '', scopes: ['html']} + { text: '', scopes: ['html'] } ], [ - {text: '', scopes: ['html']} - ], + { text: '', scopes: ['html'] } + ] ]) }) @@ -758,18 +778,18 @@ describe('TreeSitterLanguageMode', () => { editor.onDidTokenize(event => { expectTokensToEqual(editor, [ [ - {text: '<', scopes: ['html']}, - {text: 'script', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']}, + { text: '<', scopes: ['html'] }, + { text: 'script', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: 'hello', scopes: ['html', 'function']}, - {text: '();', scopes: ['html']}, + { text: 'hello', scopes: ['html', 'function'] }, + { text: '();', scopes: ['html'] } ], [ - {text: '', scopes: ['html']}, + { text: '', scopes: ['html'] } ] ]) resolve() @@ -808,7 +828,10 @@ describe('TreeSitterLanguageMode', () => { it('matches the highlighting of a freshly-opened editor', async () => { jasmine.useRealClock() - const text = fs.readFileSync(path.join(__dirname, 'fixtures', 'sample.js'), 'utf8') + const text = fs.readFileSync( + path.join(__dirname, 'fixtures', 'sample.js'), + 'utf8' + ) atom.grammars.loadGrammarSync(jsGrammarPath) atom.grammars.assignLanguageMode(buffer, 'source.js') buffer.getLanguageMode().syncOperationLimit = 0 @@ -831,7 +854,10 @@ describe('TreeSitterLanguageMode', () => { const range = getRandomBufferRange(random, buffer) if (editRoll < 2) { - const linesToInsert = buildRandomLines(random, range.getExtent().row + 1) + const linesToInsert = buildRandomLines( + random, + range.getExtent().row + 1 + ) // console.log('replace', range.toString(), JSON.stringify(linesToInsert)) buffer.setTextInRange(range, linesToInsert) } else if (editRoll < 5) { @@ -857,14 +883,15 @@ describe('TreeSitterLanguageMode', () => { // Create a fresh buffer and editor with the same text. const buffer2 = new TextBuffer(buffer.getText()) - const editor2 = new TextEditor({buffer: buffer2}) + const editor2 = new TextEditor({ buffer: buffer2 }) atom.grammars.assignLanguageMode(buffer2, 'source.js') // Verify that the the two buffers have the same syntax highlighting. await buffer.getLanguageMode().parseCompletePromise() await buffer2.getLanguageMode().parseCompletePromise() expect(buffer.getLanguageMode().tree.rootNode.toString()).toEqual( - buffer2.getLanguageMode().tree.rootNode.toString(), `Seed: ${seed}` + buffer2.getLanguageMode().tree.rootNode.toString(), + `Seed: ${seed}` ) for (let j = 0, n = editor.getScreenLineCount(); j < n; j++) { @@ -890,17 +917,17 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', folds: [ { - start: {type: '{', index: 0}, - end: {type: '}', index: -1} + start: { type: '{', index: 0 }, + end: { type: '}', index: -1 } }, { - start: {type: '(', index: 0}, - end: {type: ')', index: -1} + start: { type: '(', index: 0 }, + end: { type: ')', index: -1 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` module.exports = class A { getB (c, @@ -911,7 +938,7 @@ describe('TreeSitterLanguageMode', () => { } `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(editor.isFoldableAtBufferRow(0)).toBe(false) @@ -922,7 +949,7 @@ describe('TreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(5)).toBe(false) editor.foldBufferRow(2) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` module.exports = class A { getB (c,…) { @@ -932,7 +959,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(4) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` module.exports = class A { getB (c,…) {…} @@ -945,17 +972,17 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', folds: [ { - start: {type: '{', index: 0}, - end: {type: '}', index: -1} + start: { type: '{', index: 0 }, + end: { type: '}', index: -1 } }, { - start: {type: '(', index: 0}, - end: {type: ')', index: -1} + start: { type: '(', index: 0 }, + end: { type: ')', index: -1 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` if (a) { b } else if (c) { @@ -965,13 +992,13 @@ describe('TreeSitterLanguageMode', () => { } `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) // Avoid bringing the `else if...` up onto the same screen line as the preceding `if`. editor.foldBufferRow(1) editor.foldBufferRow(3) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` if (a) {… } else if (c) {… } else { @@ -981,7 +1008,7 @@ describe('TreeSitterLanguageMode', () => { // It's ok to bring the final `}` onto the same screen line as the preceding `else`. editor.foldBufferRow(5) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` if (a) {… } else if (c) {… } else {…} @@ -996,20 +1023,20 @@ describe('TreeSitterLanguageMode', () => { // (the closing tag). { type: 'jsx_element', - start: {index: 0}, - end: {index: -1} + start: { index: 0 }, + end: { index: -1 } }, // End the fold at the *second* to last child of the self-closing tag: the `/`. { type: 'jsx_self_closing_element', - start: {index: 1}, - end: {index: -2} + start: { index: 1 }, + end: { index: -2 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` const element1 = @@ -1020,7 +1047,7 @@ describe('TreeSitterLanguageMode', () => { `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(editor.isFoldableAtBufferRow(0)).toBe(true) @@ -1031,7 +1058,7 @@ describe('TreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(5)).toBe(false) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` const element1 = const element2 = @@ -1041,7 +1068,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(4) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` const element1 = const element2 = … @@ -1055,11 +1082,11 @@ describe('TreeSitterLanguageMode', () => { folds: [ // By default, for a node with no children, folds are started at the *end* of the first // line of a node, and ended at the *beginning* of the last line. - {type: 'comment'} + { type: 'comment' } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` /** * Important */ @@ -1068,7 +1095,7 @@ describe('TreeSitterLanguageMode', () => { */ `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(editor.isFoldableAtBufferRow(0)).toBe(true) @@ -1078,7 +1105,7 @@ describe('TreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(4)).toBe(false) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` /**… */ const x = 1 /* Also important @@ -1086,7 +1113,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(3) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` /**… */ const x = 1 /*…*/ `) @@ -1099,26 +1126,26 @@ describe('TreeSitterLanguageMode', () => { // If the #ifdef has an `#else` clause, then end the fold there. { type: ['preproc_ifdef', 'preproc_elif'], - start: {index: 1}, - end: {type: ['preproc_else', 'preproc_elif']} + start: { index: 1 }, + end: { type: ['preproc_else', 'preproc_elif'] } }, // Otherwise, end the fold at the last child - the `#endif`. { type: 'preproc_ifdef', - start: {index: 1}, - end: {index: -1} + start: { index: 1 }, + end: { index: -1 } }, // When folding an `#else` clause, the fold extends to the end of the clause. { type: 'preproc_else', - start: {index: 0} + start: { index: 0 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` #ifndef FOO_H_ #define FOO_H_ @@ -1142,11 +1169,11 @@ describe('TreeSitterLanguageMode', () => { #endif `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) editor.foldBufferRow(3) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` #ifndef FOO_H_ #define FOO_H_ @@ -1167,7 +1194,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(8) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` #ifndef FOO_H_ #define FOO_H_ @@ -1184,13 +1211,13 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` #ifndef FOO_H_… #endif `) editor.foldAllAtIndentLevel(1) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` #ifndef FOO_H_ #define FOO_H_ @@ -1210,20 +1237,20 @@ describe('TreeSitterLanguageMode', () => { folds: [ { type: 'element', - start: {index: 0}, - end: {index: -1} + start: { index: 0 }, + end: { index: -1 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) // Void elements have only one child @@ -1231,7 +1258,7 @@ describe('TreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(2)).toBe(false) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` … `) @@ -1245,13 +1272,13 @@ describe('TreeSitterLanguageMode', () => { // just to demonstrate the targeting of named vs anonymous nodes. { type: 'elsif', - start: {index: 1}, + start: { index: 1 }, // There are no double quotes around the `elsif` type. This indicates // that we're targeting a *named* node in the syntax tree. The fold // should end at the nested `elsif` node, not at the token that represents // the literal string "elsif". - end: {type: ['else', 'elsif']} + end: { type: ['else', 'elsif'] } }, { type: 'else', @@ -1260,12 +1287,12 @@ describe('TreeSitterLanguageMode', () => { // we're targetting an *anonymous* node in the syntax tree. The fold // should start at the token representing the literal string "else", // not at an `else` node. - start: {type: '"else"'} + start: { type: '"else"' } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` if a b elsif c @@ -1275,20 +1302,20 @@ describe('TreeSitterLanguageMode', () => { end `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(languageMode.tree.rootNode.toString()).toBe( - "(program (if (identifier) (then " + - "(identifier)) " + - "(elsif (identifier) (then " + - "(identifier)) " + - "(else " + - "(identifier)))))" + '(program (if (identifier) (then ' + + '(identifier)) ' + + '(elsif (identifier) (then ' + + '(identifier)) ' + + '(else ' + + '(identifier)))))' ) editor.foldBufferRow(2) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` if a b elsif c… @@ -1298,7 +1325,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(4) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` if a b elsif c… @@ -1312,13 +1339,13 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', folds: [ { - start: {type: '{', index: 0}, - end: {type: '}', index: -1} + start: { type: '{', index: 0 }, + end: { type: '}', index: -1 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` class A { // a constructor (b) { @@ -1327,7 +1354,7 @@ describe('TreeSitterLanguageMode', () => { } `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(languageMode.isFoldableAtRow(0)).toBe(true) expect(languageMode.isFoldableAtRow(1)).toBe(false) @@ -1345,17 +1372,21 @@ describe('TreeSitterLanguageMode', () => { describe('when folding a node that ends with a line break', () => { it('ends the fold at the end of the previous line', async () => { - const grammar = new TreeSitterGrammar(atom.grammars, pythonGrammarPath, { - parser: 'tree-sitter-python', - folds: [ - { - type: 'function_definition', - start: {type: ':'} - } - ] - }) + const grammar = new TreeSitterGrammar( + atom.grammars, + pythonGrammarPath, + { + parser: 'tree-sitter-python', + folds: [ + { + type: 'function_definition', + start: { type: ':' } + } + ] + } + ) - buffer.setText(dedent ` + buffer.setText(dedent` def ab(): print 'a' print 'b' @@ -1365,10 +1396,10 @@ describe('TreeSitterLanguageMode', () => { print 'd' `) - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` def ab():… def cd(): @@ -1379,31 +1410,39 @@ describe('TreeSitterLanguageMode', () => { }) it('folds code in injected languages', async () => { - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: {}, - folds: [{ - type: ['element', 'raw_element'], - start: {index: 0}, - end: {index: -1} - }], - injectionRegExp: 'html' - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: {}, + folds: [ + { + type: ['element', 'raw_element'], + start: { index: 0 }, + end: { index: -1 } + } + ], + injectionRegExp: 'html' + } + ) const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: {}, - folds: [{ - type: ['template_string'], - start: {index: 0}, - end: {index: -1}, - }, - { - start: {index: 0, type: '('}, - end: {index: -1, type: ')'} - }], + folds: [ + { + type: ['template_string'], + start: { index: 0 }, + end: { index: -1 } + }, + { + start: { index: 0, type: '(' }, + end: { index: -1, type: ')' } + } + ], injectionRegExp: 'javascript', injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) @@ -1422,7 +1461,11 @@ describe('TreeSitterLanguageMode', () => { \` ` ) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: jsGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: jsGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) editor.foldBufferRow(2) @@ -1467,32 +1510,32 @@ describe('TreeSitterLanguageMode', () => { buffer.setText('foo({bar: baz});') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.scopeDescriptorForBufferPosition([0, 'foo({b'.length]).getScopesArray()).toEqual([ - 'source.js', - 'property.name' - ]) - expect(editor.scopeDescriptorForBufferPosition([0, 'foo({'.length]).getScopesArray()).toEqual([ - 'source.js', - 'property.name' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor + .scopeDescriptorForBufferPosition([0, 'foo({b'.length]) + .getScopesArray() + ).toEqual(['source.js', 'property.name']) + expect( + editor + .scopeDescriptorForBufferPosition([0, 'foo({'.length]) + .getScopesArray() + ).toEqual(['source.js', 'property.name']) // Drive-by test for .tokenForPosition() const token = editor.tokenForBufferPosition([0, 'foo({b'.length]) expect(token.value).toBe('bar') - expect(token.scopes).toEqual([ - 'source.js', - 'property.name' - ]) + expect(token.scopes).toEqual(['source.js', 'property.name']) buffer.setText('// baz\n') // Adjust position when at end of line - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.scopeDescriptorForBufferPosition([0, '// baz'.length]).getScopesArray()).toEqual([ - 'source.js', - 'comment.block' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor + .scopeDescriptorForBufferPosition([0, '// baz'.length]) + .getScopesArray() + ).toEqual(['source.js', 'comment.block']) }) it('includes nodes in injected syntax trees', async () => { @@ -1509,16 +1552,20 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'text.html', - parser: 'tree-sitter-html', - scopes: { - fragment: 'text.html', - raw_element: 'script.tag' - }, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'text.html', + parser: 'tree-sitter-html', + scopes: { + fragment: 'text.html', + raw_element: 'script.tag' + }, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1533,11 +1580,17 @@ describe('TreeSitterLanguageMode', () => {
`) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const position = buffer.findSync('name').start - expect(languageMode.scopeDescriptorForPosition(position).getScopesArray()).toEqual([ + expect( + languageMode.scopeDescriptorForPosition(position).getScopesArray() + ).toEqual([ 'text.html', 'script.tag', 'source.js', @@ -1558,10 +1611,10 @@ describe('TreeSitterLanguageMode', () => { }) buffer.setText('a; ') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray()).toEqual([ - 'source.js' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray() + ).toEqual(['source.js']) }) it('works when the given position is between tokens', () => { @@ -1570,19 +1623,18 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', scopes: { program: 'source.js', - comment: 'comment.block', + comment: 'comment.block' } }) buffer.setText('a // b') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.scopeDescriptorForBufferPosition([0, 2]).getScopesArray()).toEqual([ - 'source.js' - ]) - expect(editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray()).toEqual([ - 'source.js', - 'comment.block' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor.scopeDescriptorForBufferPosition([0, 2]).getScopesArray() + ).toEqual(['source.js']) + expect( + editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray() + ).toEqual(['source.js', 'comment.block']) }) }) @@ -1595,8 +1647,12 @@ describe('TreeSitterLanguageMode', () => { buffer.setText('foo({bar: baz});') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.syntaxTreeScopeDescriptorForBufferPosition([0, 6]).getScopesArray()).toEqual([ + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor + .syntaxTreeScopeDescriptorForBufferPosition([0, 6]) + .getScopesArray() + ).toEqual([ 'source.js', 'program', 'expression_statement', @@ -1609,12 +1665,12 @@ describe('TreeSitterLanguageMode', () => { buffer.setText('//bar\n') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.syntaxTreeScopeDescriptorForBufferPosition([0, 5]).getScopesArray()).toEqual([ - 'source.js', - 'program', - 'comment' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor + .syntaxTreeScopeDescriptorForBufferPosition([0, 5]) + .getScopesArray() + ).toEqual(['source.js', 'program', 'comment']) }) it('includes nodes in injected syntax trees', async () => { @@ -1626,13 +1682,17 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'text.html', - parser: 'tree-sitter-html', - scopes: {}, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'text.html', + parser: 'tree-sitter-html', + scopes: {}, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1647,11 +1707,19 @@ describe('TreeSitterLanguageMode', () => { `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const position = buffer.findSync('name').start - expect(editor.syntaxTreeScopeDescriptorForBufferPosition(position).getScopesArray()).toEqual([ + expect( + editor + .syntaxTreeScopeDescriptorForBufferPosition(position) + .getScopesArray() + ).toEqual([ 'text.html', 'fragment', 'element', @@ -1680,13 +1748,15 @@ describe('TreeSitterLanguageMode', () => { buffer.setText('foo({bar: baz});') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.bufferRangeForScopeAtPosition(null, [0, 6])).toEqual( - [[0, 5], [0, 8]] - ) - expect(editor.bufferRangeForScopeAtPosition(null, [0, 9])).toEqual( - [[0, 8], [0, 9]] - ) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect(editor.bufferRangeForScopeAtPosition(null, [0, 6])).toEqual([ + [0, 5], + [0, 8] + ]) + expect(editor.bufferRangeForScopeAtPosition(null, [0, 9])).toEqual([ + [0, 8], + [0, 9] + ]) }) it('includes nodes in injected syntax trees', async () => { @@ -1698,13 +1768,17 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: {}, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: {}, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1719,14 +1793,19 @@ describe('TreeSitterLanguageMode', () => { `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const nameProperty = buffer.findSync('name') - const {start} = nameProperty - const position = Object.assign({}, start, {column: start.column + 2}) - expect(languageMode.bufferRangeForScopeAtPosition(null, position)) - .toEqual(nameProperty) + const { start } = nameProperty + const position = Object.assign({}, start, { column: start.column + 2 }) + expect( + languageMode.bufferRangeForScopeAtPosition(null, position) + ).toEqual(nameProperty) }) }) @@ -1736,20 +1815,20 @@ describe('TreeSitterLanguageMode', () => { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'variable.other.object.property', - 'template_string': 'string.quoted.template' + property_identifier: 'variable.other.object.property', + template_string: 'string.quoted.template' } }) buffer.setText('a(`${b({ccc: ddd})} eee`);') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.bufferRangeForScopeAtPosition('.variable.property', [0, 9])).toEqual( - [[0, 8], [0, 11]] - ) - expect(editor.bufferRangeForScopeAtPosition('.string.quoted', [0, 6])).toEqual( - [[0, 2], [0, 24]] - ) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor.bufferRangeForScopeAtPosition('.variable.property', [0, 9]) + ).toEqual([[0, 8], [0, 11]]) + expect( + editor.bufferRangeForScopeAtPosition('.string.quoted', [0, 6]) + ).toEqual([[0, 2], [0, 24]]) }) it('includes nodes in injected syntax trees', async () => { @@ -1757,21 +1836,25 @@ describe('TreeSitterLanguageMode', () => { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'variable.other.object.property', + property_identifier: 'variable.other.object.property' }, injectionRegExp: 'javascript', injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: { - 'element': 'meta.element.html' - }, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: { + element: 'meta.element.html' + }, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1786,16 +1869,28 @@ describe('TreeSitterLanguageMode', () => { `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const nameProperty = buffer.findSync('name') - const {start} = nameProperty - const position = Object.assign({}, start, {column: start.column + 2}) - expect(languageMode.bufferRangeForScopeAtPosition('.object.property', position)) - .toEqual(nameProperty) - expect(languageMode.bufferRangeForScopeAtPosition('.meta.element.html', position)) - .toEqual(buffer.findSync('\\${person\\.name}')) + const { start } = nameProperty + const position = Object.assign({}, start, { column: start.column + 2 }) + expect( + languageMode.bufferRangeForScopeAtPosition( + '.object.property', + position + ) + ).toEqual(nameProperty) + expect( + languageMode.bufferRangeForScopeAtPosition( + '.meta.element.html', + position + ) + ).toEqual(buffer.findSync('\\${person\\.name}')) }) it('accepts node-matching functions as selectors', async () => { @@ -1807,13 +1902,17 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: {}, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: {}, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1828,16 +1927,25 @@ describe('TreeSitterLanguageMode', () => { `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const nameProperty = buffer.findSync('name') - const {start} = nameProperty - const position = Object.assign({}, start, {column: start.column + 2}) + const { start } = nameProperty + const position = Object.assign({}, start, { column: start.column + 2 }) const templateStringInCallExpression = node => - node.type === 'template_string' && node.parent.type === 'call_expression' - expect(languageMode.bufferRangeForScopeAtPosition(templateStringInCallExpression, position)) - .toEqual([[3, 19], [5, 15]]) + node.type === 'template_string' && + node.parent.type === 'call_expression' + expect( + languageMode.bufferRangeForScopeAtPosition( + templateStringInCallExpression, + position + ) + ).toEqual([[3, 19], [5, 15]]) }) }) }) @@ -1850,16 +1958,16 @@ describe('TreeSitterLanguageMode', () => { }) buffer.setText('foo(bar({x: 2}));') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(languageMode.getSyntaxNodeAtPosition([0, 6]).range).toEqual( buffer.findSync('bar') ) const findFoo = node => node.type === 'call_expression' && node.firstChild.text === 'foo' - expect(languageMode.getSyntaxNodeAtPosition([0, 6], findFoo).range).toEqual( - [[0, 0], [0, buffer.getText().length - 1]] - ) + expect( + languageMode.getSyntaxNodeAtPosition([0, 6], findFoo).range + ).toEqual([[0, 0], [0, buffer.getText().length - 1]]) }) }) @@ -1868,26 +1976,35 @@ describe('TreeSitterLanguageMode', () => { const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { scopeName: 'javascript', parser: 'tree-sitter-javascript', - comments: {start: '//'}, + comments: { start: '//' }, injectionRegExp: 'javascript', injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: {}, - comments: {start: ''}, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: {}, + comments: { start: '' }, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) - buffer.setText(` + buffer.setText( + `
hi
- `.trim()) + `.trim() + ) + const htmlCommentStrings = { + commentStartString: '' + } + const jsCommentStrings = { + commentStartString: '//', + commentEndString: undefined + } - const htmlCommentStrings = {commentStartString: ''} - const jsCommentStrings = {commentStartString: '//', commentEndString: undefined} - - expect(languageMode.commentStringsForPosition(new Point(0, 0))).toEqual(htmlCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(1, 0))).toEqual(htmlCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(2, 0))).toEqual(jsCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(3, 0))).toEqual(jsCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(4, 0))).toEqual(htmlCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(5, 0))).toEqual(jsCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(6, 0))).toEqual(htmlCommentStrings) + expect(languageMode.commentStringsForPosition(new Point(0, 0))).toEqual( + htmlCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(1, 0))).toEqual( + htmlCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(2, 0))).toEqual( + jsCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(3, 0))).toEqual( + jsCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(4, 0))).toEqual( + htmlCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(5, 0))).toEqual( + jsCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(6, 0))).toEqual( + htmlCommentStrings + ) }) }) @@ -1915,17 +2052,17 @@ describe('TreeSitterLanguageMode', () => { it('expands and contracts the selection based on the syntax tree', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', - scopes: {'program': 'source'} + scopes: { program: 'source' } }) - buffer.setText(dedent ` + buffer.setText(dedent` function a (b, c, d) { eee.f() g() } `) - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) editor.setCursorBufferPosition([1, 3]) editor.selectLargerSyntaxNode() @@ -1937,7 +2074,9 @@ describe('TreeSitterLanguageMode', () => { editor.selectLargerSyntaxNode() expect(editor.getSelectedText()).toBe('{\n eee.f()\n g()\n}') editor.selectLargerSyntaxNode() - expect(editor.getSelectedText()).toBe('function a (b, c, d) {\n eee.f()\n g()\n}') + expect(editor.getSelectedText()).toBe( + 'function a (b, c, d) {\n eee.f()\n g()\n}' + ) editor.selectSmallerSyntaxNode() expect(editor.getSelectedText()).toBe('{\n eee.f()\n g()\n}') @@ -1956,9 +2095,9 @@ describe('TreeSitterLanguageMode', () => { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'property', + property_identifier: 'property', 'call_expression > identifier': 'function', - 'template_string': 'string', + template_string: 'string', 'template_substitution > "${"': 'interpolation', 'template_substitution > "}"': 'interpolation' }, @@ -1966,24 +2105,35 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: { - fragment: 'html', - tag_name: 'tag', - attribute_name: 'attr' - }, - injectionRegExp: 'html' - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: { + fragment: 'html', + tag_name: 'tag', + attribute_name: 'attr' + }, + injectionRegExp: 'html' + } + ) atom.grammars.addGrammar(htmlGrammar) buffer.setText('a = html ` c${def()}e${f}g `') - const languageMode = new TreeSitterLanguageMode({buffer, grammar: jsGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: jsGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) - editor.setCursorBufferPosition({row: 0, column: buffer.getText().indexOf('ef()')}) + editor.setCursorBufferPosition({ + row: 0, + column: buffer.getText().indexOf('ef()') + }) editor.selectLargerSyntaxNode() expect(editor.getSelectedText()).toBe('def') editor.selectLargerSyntaxNode() @@ -2023,7 +2173,6 @@ function expectTokensToEqual (editor, expectedTokenLines) { // Assert that the correct tokens are returned regardless of which row // the highlighting iterator starts on. for (let startRow = 0; startRow <= lastRow; startRow++) { - // Clear the screen line cache between iterations, but not on the first // iteration, so that the first iteration tests that the cache has been // correctly invalidated by any changes. @@ -2035,13 +2184,17 @@ function expectTokensToEqual (editor, expectedTokenLines) { const tokenLines = [] for (let row = startRow; row <= lastRow; row++) { - tokenLines[row] = editor.tokensForScreenRow(row).map(({text, scopes}) => ({ - text, - scopes: scopes.map(scope => scope - .split(' ') - .map(className => className.replace('syntax--', '')) - .join(' ')) - })) + tokenLines[row] = editor + .tokensForScreenRow(row) + .map(({ text, scopes }) => ({ + text, + scopes: scopes.map(scope => + scope + .split(' ') + .map(className => className.replace('syntax--', '')) + .join(' ') + ) + })) } for (let row = startRow; row <= lastRow; row++) { @@ -2050,7 +2203,10 @@ function expectTokensToEqual (editor, expectedTokenLines) { expect(tokenLine.length).toEqual(expectedTokenLine.length) for (let i = 0; i < tokenLine.length; i++) { - expect(tokenLine[i]).toEqual(expectedTokenLine[i], `Token ${i}, startRow: ${startRow}`) + expect(tokenLine[i]).toEqual( + expectedTokenLine[i], + `Token ${i}, startRow: ${startRow}` + ) } } } @@ -2063,7 +2219,10 @@ function expectTokensToEqual (editor, expectedTokenLines) { const HTML_TEMPLATE_LITERAL_INJECTION_POINT = { type: 'call_expression', language (node) { - if (node.lastChild.type === 'template_string' && node.firstChild.type === 'identifier') { + if ( + node.lastChild.type === 'template_string' && + node.firstChild.type === 'identifier' + ) { return node.firstChild.text } }, @@ -2074,6 +2233,10 @@ const HTML_TEMPLATE_LITERAL_INJECTION_POINT = { const SCRIPT_TAG_INJECTION_POINT = { type: 'raw_element', - language () { return 'javascript' }, - content (node) { return node.child(1) } + language () { + return 'javascript' + }, + content (node) { + return node.child(1) + } } diff --git a/spec/update-process-env-spec.js b/spec/update-process-env-spec.js index f7948d998..db702bd5b 100644 --- a/spec/update-process-env-spec.js +++ b/spec/update-process-env-spec.js @@ -1,12 +1,22 @@ /** @babel */ /* eslint-env jasmine */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + 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 { EventEmitter } from 'events' import mockSpawn from 'mock-spawn' const temp = require('temp').track() @@ -46,7 +56,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 +90,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 +124,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 +156,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 +168,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 +181,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 +203,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 +218,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 +260,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 +291,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 +325,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 +338,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 () { diff --git a/spec/uri-handler-registry-spec.js b/spec/uri-handler-registry-spec.js index d2da93087..b17bfa16e 100644 --- a/spec/uri-handler-registry-spec.js +++ b/spec/uri-handler-registry-spec.js @@ -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', diff --git a/spec/view-registry-spec.js b/spec/view-registry-spec.js index db8b077f1..b38ffa5f3 100644 --- a/spec/view-registry-spec.js +++ b/spec/view-registry-spec.js @@ -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 + }) }) - }) - ) + })) }) diff --git a/spec/window-event-handler-spec.js b/spec/window-event-handler-spec.js index b5000388c..6f840f3bf 100644 --- a/spec/window-event-handler-spec.js +++ b/spec/window-event-handler-spec.js @@ -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() - }) - ) + })) }) diff --git a/spec/workspace-center-spec.js b/spec/workspace-center-spec.js index 7c01078c3..055b463db 100644 --- a/spec/workspace-center-spec.js +++ b/spec/workspace-center-spec.js @@ -2,7 +2,14 @@ const TextEditor = require('../src/text-editor') -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' describe('WorkspaceCenter', () => { describe('.observeTextEditors()', () => { @@ -12,20 +19,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 + ]) }) }) }) diff --git a/spec/workspace-element-spec.js b/spec/workspace-element-spec.js index 7564f6931..b11e8b443 100644 --- a/spec/workspace-element-spec.js +++ b/spec/workspace-element-spec.js @@ -1,11 +1,18 @@ /** @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, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise @@ -35,19 +42,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 pane1, + pane2, + pane3, + pane4, + pane5, + pane6, + pane7, + pane8, + pane9, + 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 @@ -104,14 +131,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 +152,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 +164,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 +186,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 +199,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 +220,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 +232,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 +244,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 +257,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 +278,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 +290,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 +302,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 +318,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 +345,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 +362,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 +379,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 +396,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 +416,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 +425,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 +435,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 +451,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 +460,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 +470,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 +486,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 +495,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 +505,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 +521,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 +530,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 +540,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 +557,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 +578,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 +602,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 +643,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 +670,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 +686,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 +713,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 +729,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 +756,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 +775,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 +793,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 +823,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 +851,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 +862,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 +911,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 +954,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 +976,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 +1017,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' } } + ) }) }) }) diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index 091588a70..265ae2ba9 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -10,7 +10,15 @@ const _ = require('underscore-plus') const fstream = require('fstream') const fs = require('fs-plus') const AtomEnvironment = require('../src/atom-environment') -const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach, + conditionPromise +} = require('./async-spec-helpers') describe('Workspace', () => { let workspace @@ -20,7 +28,10 @@ describe('Workspace', () => { workspace = atom.workspace workspace.resetFontSize() spyOn(atom.applicationDelegate, 'confirm') - setDocumentEdited = spyOn(atom.applicationDelegate, 'setWindowDocumentEdited') + setDocumentEdited = spyOn( + atom.applicationDelegate, + 'setWindowDocumentEdited' + ) atom.project.setPaths([atom.project.getDirectories()[0].resolve('dir')]) waits(1) @@ -35,10 +46,10 @@ describe('Workspace', () => { } }) - function simulateReload() { + function simulateReload () { waitsForPromise(() => { const workspaceState = workspace.serialize() - const projectState = atom.project.serialize({isUnloading: true}) + const projectState = atom.project.serialize({ isUnloading: true }) workspace.destroy() atom.project.destroy() atom.project = new Project({ @@ -71,18 +82,26 @@ describe('Workspace', () => { describe('when the workspace contains text editors', () => { it('constructs the view with the same panes', () => { const pane1 = atom.workspace.getActivePane() - const pane2 = pane1.splitRight({copyActiveItem: true}) - const pane3 = pane2.splitRight({copyActiveItem: true}) + const pane2 = pane1.splitRight({ copyActiveItem: true }) + const pane3 = pane2.splitRight({ copyActiveItem: true }) let pane4 = null - waitsForPromise(() => atom.workspace.open(null).then(editor => editor.setText('An untitled editor.'))) - waitsForPromise(() => - atom.workspace.open('b').then(editor => pane2.activateItem(editor.copy())) + atom.workspace + .open(null) + .then(editor => editor.setText('An untitled editor.')) ) waitsForPromise(() => - atom.workspace.open('../sample.js').then(editor => pane3.activateItem(editor)) + atom.workspace + .open('b') + .then(editor => pane2.activateItem(editor.copy())) + ) + + waitsForPromise(() => + atom.workspace + .open('../sample.js') + .then(editor => pane3.activateItem(editor)) ) runs(() => { @@ -91,7 +110,9 @@ describe('Workspace', () => { }) waitsForPromise(() => - atom.workspace.open('../sample.txt').then(editor => pane4.activateItem(editor)) + atom.workspace + .open('../sample.txt') + .then(editor => pane4.activateItem(editor)) ) runs(() => { @@ -103,11 +124,19 @@ describe('Workspace', () => { runs(() => { expect(atom.workspace.getTextEditors().length).toBe(5) - const [editor1, editor2, untitledEditor, editor3, editor4] = atom.workspace.getTextEditors() + const [ + editor1, + editor2, + untitledEditor, + editor3, + editor4 + ] = atom.workspace.getTextEditors() const firstDirectory = atom.project.getDirectories()[0] expect(firstDirectory).toBeDefined() expect(editor1.getPath()).toBe(firstDirectory.resolve('b')) - expect(editor2.getPath()).toBe(firstDirectory.resolve('../sample.txt')) + expect(editor2.getPath()).toBe( + firstDirectory.resolve('../sample.txt') + ) expect(editor2.getCursorScreenPosition()).toEqual([0, 2]) expect(editor3.getPath()).toBe(firstDirectory.resolve('b')) expect(editor4.getPath()).toBe(firstDirectory.resolve('../sample.js')) @@ -115,9 +144,17 @@ describe('Workspace', () => { expect(untitledEditor.getPath()).toBeUndefined() expect(untitledEditor.getText()).toBe('An untitled editor.') - expect(atom.workspace.getActiveTextEditor().getPath()).toBe(editor3.getPath()) - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${path.basename(editor3.getLongTitle())} \\u2014 ${pathEscaped}`)) + expect(atom.workspace.getActiveTextEditor().getPath()).toBe( + editor3.getPath() + ) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp( + `^${path.basename(editor3.getLongTitle())} \\u2014 ${pathEscaped}` + ) + ) }) }) }) @@ -150,25 +187,47 @@ describe('Workspace', () => { let editor1 let editor2 - waitsForPromise(() => workspace.open().then(editor => { editor1 = editor })) + waitsForPromise(() => + workspace.open().then(editor => { + editor1 = editor + }) + ) runs(() => { expect(editor1.getPath()).toBeUndefined() expect(workspace.getActivePane().items).toEqual([editor1]) expect(workspace.getActivePaneItem()).toBe(editor1) expect(workspace.getActivePane().activate).toHaveBeenCalled() - expect(openEvents).toEqual([{uri: undefined, pane: workspace.getActivePane(), item: editor1, index: 0}]) + expect(openEvents).toEqual([ + { + uri: undefined, + pane: workspace.getActivePane(), + item: editor1, + index: 0 + } + ]) openEvents = [] }) - waitsForPromise(() => workspace.open().then(editor => { editor2 = editor })) + waitsForPromise(() => + workspace.open().then(editor => { + editor2 = editor + }) + ) runs(() => { expect(editor2.getPath()).toBeUndefined() expect(workspace.getActivePane().items).toEqual([editor1, editor2]) expect(workspace.getActivePaneItem()).toBe(editor2) expect(workspace.getActivePane().activate).toHaveBeenCalled() - expect(openEvents).toEqual([{uri: undefined, pane: workspace.getActivePane(), item: editor2, index: 1}]) + expect(openEvents).toEqual([ + { + uri: undefined, + pane: workspace.getActivePane(), + item: editor2, + index: 1 + } + ]) }) }) }) @@ -185,7 +244,9 @@ describe('Workspace', () => { editor1 = o return workspace.open('b').then(o => { editor2 = o - return workspace.open('a').then(o => { editor = o }) + return workspace.open('a').then(o => { + editor = o + }) }) }) ) @@ -229,7 +290,9 @@ describe('Workspace', () => { } dock.getActivePane().addItem(item) expect(dock.getPaneItems()).toHaveLength(1) - waitsForPromise(() => atom.workspace.open(ITEM_URI, {searchAllPanes: true})) + waitsForPromise(() => + atom.workspace.open(ITEM_URI, { searchAllPanes: true }) + ) runs(() => { expect(atom.workspace.getPaneItems()).toHaveLength(1) expect(dock.getPaneItems()).toHaveLength(1) @@ -242,7 +305,11 @@ describe('Workspace', () => { it('adds the item to the workspace', () => { let editor waitsForPromise(() => workspace.open('a')) - waitsForPromise(() => workspace.open('b', {activateItem: false}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('b', { activateItem: false }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getPaneItems()).toContain(editor) expect(workspace.getActivePaneItem()).not.toBe(editor) @@ -262,7 +329,11 @@ describe('Workspace', () => { it('adds and activates a new editor for the given path on the active pane', () => { let editor = null - waitsForPromise(() => workspace.open('a').then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a').then(o => { + editor = o + }) + ) runs(() => { const firstDirectory = atom.project.getDirectories()[0] @@ -278,10 +349,16 @@ describe('Workspace', () => { let editor0 = null let editor1 = null - waitsForPromise(() => Promise.all([ - workspace.open('spartacus.txt').then(o0 => { editor0 = o0 }), - workspace.open('spartacus.txt').then(o1 => { editor1 = o1 }), - ])) + waitsForPromise(() => + Promise.all([ + workspace.open('spartacus.txt').then(o0 => { + editor0 = o0 + }), + workspace.open('spartacus.txt').then(o1 => { + editor1 = o1 + }) + ]) + ) runs(() => { expect(editor0).toEqual(editor1) @@ -296,7 +373,9 @@ describe('Workspace', () => { } const opener = jasmine.createSpy().andReturn(item) const dock = atom.workspace.getRightDock() - spyOn(atom.workspace.itemLocationStore, 'load').andReturn(Promise.resolve()) + spyOn(atom.workspace.itemLocationStore, 'load').andReturn( + Promise.resolve() + ) spyOn(atom.workspace, 'getOpeners').andReturn([opener]) expect(dock.getPaneItems()).toHaveLength(0) waitsForPromise(() => atom.workspace.open('a')) @@ -314,10 +393,12 @@ describe('Workspace', () => { getDefaultLocation: () => 'left', getElement: () => document.createElement('div') } - const opener = uri => uri === ITEM_URI ? item : null + const opener = uri => (uri === ITEM_URI ? item : null) const dock = atom.workspace.getRightDock() spyOn(atom.workspace.itemLocationStore, 'load').andCallFake(uri => - uri === 'atom://test' ? Promise.resolve('right') : Promise.resolve() + uri === 'atom://test' + ? Promise.resolve('right') + : Promise.resolve() ) spyOn(atom.workspace, 'getOpeners').andReturn([opener]) expect(dock.getPaneItems()).toHaveLength(0) @@ -331,18 +412,26 @@ describe('Workspace', () => { }) describe('when an item with the given uri exists in an inactive pane container', () => { - it('activates that item if it is in that container\'s active pane', async () => { + it("activates that item if it is in that container's active pane", async () => { const item = await atom.workspace.open('a') atom.workspace.getLeftDock().activate() - expect(await atom.workspace.open('a', {searchAllPanes: false})).toBe(item) - expect(atom.workspace.getActivePaneContainer().getLocation()).toBe('center') + expect( + await atom.workspace.open('a', { searchAllPanes: false }) + ).toBe(item) + expect(atom.workspace.getActivePaneContainer().getLocation()).toBe( + 'center' + ) expect(atom.workspace.getPaneItems()).toEqual([item]) atom.workspace.getActivePane().splitRight() atom.workspace.getLeftDock().activate() - const item2 = await atom.workspace.open('a', {searchAllPanes: false}) + const item2 = await atom.workspace.open('a', { + searchAllPanes: false + }) expect(item2).not.toBe(item) - expect(atom.workspace.getActivePaneContainer().getLocation()).toBe('center') + expect(atom.workspace.getActivePaneContainer().getLocation()).toBe( + 'center' + ) expect(atom.workspace.getPaneItems()).toEqual([item, item2]) }) }) @@ -358,17 +447,21 @@ describe('Workspace', () => { waitsForPromise(() => { pane1.activate() - return workspace.open('a').then(o => { editor1 = o }) + return workspace.open('a').then(o => { + editor1 = o + }) }) waitsForPromise(() => { pane2.activate() - return workspace.open('b').then(o => { editor2 = o }) + return workspace.open('b').then(o => { + editor2 = o + }) }) runs(() => expect(workspace.getActivePaneItem()).toBe(editor2)) - waitsForPromise(() => workspace.open('a', {searchAllPanes: true})) + waitsForPromise(() => workspace.open('a', { searchAllPanes: true })) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -383,9 +476,17 @@ describe('Workspace', () => { const pane1 = workspace.getActivePane().splitRight() pane0.activate() - const promise0 = workspace.open('spartacus.txt', {searchAllPanes: true}).then(o0 => { editor0 = o0 }) + const promise0 = workspace + .open('spartacus.txt', { searchAllPanes: true }) + .then(o0 => { + editor0 = o0 + }) pane1.activate() - const promise1 = workspace.open('spartacus.txt', {searchAllPanes: true}).then(o1 => { editor1 = o1 }) + const promise1 = workspace + .open('spartacus.txt', { searchAllPanes: true }) + .then(o1 => { + editor1 = o1 + }) waitsForPromise(() => Promise.all([promise0, promise1])) @@ -408,7 +509,9 @@ describe('Workspace', () => { } dock.getActivePane().addItem(item) spyOn(dock.paneForItem(item), 'activate') - waitsForPromise(() => atom.workspace.open(ITEM_URI, {searchAllPanes: true})) + waitsForPromise(() => + atom.workspace.open(ITEM_URI, { searchAllPanes: true }) + ) runs(() => expect(dock.paneForItem(item).activate).toHaveBeenCalled()) }) }) @@ -416,7 +519,11 @@ describe('Workspace', () => { describe('when no editor for the given uri is open in any pane', () => { it('opens an editor for the given uri in the active pane', () => { let editor = null - waitsForPromise(() => workspace.open('a', {searchAllPanes: true}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { searchAllPanes: true }).then(o => { + editor = o + }) + ) runs(() => expect(workspace.getActivePaneItem()).toBe(editor)) }) @@ -425,8 +532,13 @@ describe('Workspace', () => { describe('when attempting to open an editor in a dock', () => { it('opens the editor in the workspace center', async () => { - await atom.workspace.open('sample.txt', {location: 'right'}) - expect(atom.workspace.getCenter().getActivePaneItem().getFileName()).toEqual('sample.txt') + await atom.workspace.open('sample.txt', { location: 'right' }) + expect( + atom.workspace + .getCenter() + .getActivePaneItem() + .getFileName() + ).toEqual('sample.txt') }) }) @@ -457,7 +569,7 @@ describe('Workspace', () => { const item = document.createElement('div') await atom.workspace.open(item) - await atom.workspace.open(null, {split: 'right'}) + await atom.workspace.open(null, { split: 'right' }) expect(atom.workspace.getActivePaneItem()).not.toBe(item) expect(atom.workspace.getActivePane().getItems().length).toBe(1) @@ -468,7 +580,9 @@ describe('Workspace', () => { rejection = error } - expect(rejection.message).toMatch(/The workspace can only contain one instance of item/) + expect(rejection.message).toMatch( + /The workspace can only contain one instance of item/ + ) }) }) }) @@ -481,7 +595,11 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane2) let editor = null - waitsForPromise(() => workspace.open('a', {split: 'left'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'left' }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -492,7 +610,9 @@ describe('Workspace', () => { // Focus right pane and reopen the file on the left waitsForPromise(() => { pane2.focus() - return workspace.open('a', {split: 'left'}).then(o => { editor = o }) + return workspace.open('a', { split: 'left' }).then(o => { + editor = o + }) }) runs(() => { @@ -512,7 +632,11 @@ describe('Workspace', () => { pane1.activate() expect(workspace.getActivePane()).toBe(pane1) - waitsForPromise(() => workspace.open('a', {split: 'left'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'left' }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -526,7 +650,11 @@ describe('Workspace', () => { let editor = null const pane1 = workspace.getActivePane() let pane2 = null - waitsForPromise(() => workspace.open('a', {split: 'right'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'right' }).then(o => { + editor = o + }) + ) runs(() => { pane2 = workspace.getPanes().filter(p => p !== pane1)[0] @@ -538,7 +666,9 @@ describe('Workspace', () => { // Focus right pane and reopen the file on the right waitsForPromise(() => { pane1.focus() - return workspace.open('a', {split: 'right'}).then(o => { editor = o }) + return workspace.open('a', { split: 'right' }).then(o => { + editor = o + }) }) runs(() => { @@ -558,14 +688,22 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane1) let pane4 = null - waitsForPromise(() => workspace.open('a', {split: 'right'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'right' }).then(o => { + editor = o + }) + ) runs(() => { pane4 = workspace.getPanes().filter(p => p !== pane1)[0] expect(workspace.getActivePane()).toBe(pane4) expect(pane4.items).toEqual([editor]) - expect(workspace.getCenter().paneContainer.root.children[0]).toBe(pane1) - expect(workspace.getCenter().paneContainer.root.children[1]).toBe(pane4) + expect(workspace.getCenter().paneContainer.root.children[0]).toBe( + pane1 + ) + expect(workspace.getCenter().paneContainer.root.children[1]).toBe( + pane4 + ) }) }) }) @@ -578,7 +716,11 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane2) let editor = null - waitsForPromise(() => workspace.open('a', {split: 'up'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'up' }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -589,7 +731,9 @@ describe('Workspace', () => { // Focus bottom pane and reopen the file on the top waitsForPromise(() => { pane2.focus() - return workspace.open('a', {split: 'up'}).then(o => { editor = o }) + return workspace.open('a', { split: 'up' }).then(o => { + editor = o + }) }) runs(() => { @@ -609,7 +753,11 @@ describe('Workspace', () => { pane1.activate() expect(workspace.getActivePane()).toBe(pane1) - waitsForPromise(() => workspace.open('a', {split: 'up'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'up' }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -623,7 +771,11 @@ describe('Workspace', () => { let editor = null const pane1 = workspace.getActivePane() let pane2 = null - waitsForPromise(() => workspace.open('a', {split: 'down'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'down' }).then(o => { + editor = o + }) + ) runs(() => { pane2 = workspace.getPanes().filter(p => p !== pane1)[0] @@ -635,7 +787,9 @@ describe('Workspace', () => { // Focus bottom pane and reopen the file on the right waitsForPromise(() => { pane1.focus() - return workspace.open('a', {split: 'down'}).then(o => { editor = o }) + return workspace.open('a', { split: 'down' }).then(o => { + editor = o + }) }) runs(() => { @@ -654,14 +808,22 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane1) let pane4 = null - waitsForPromise(() => workspace.open('a', {split: 'down'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'down' }).then(o => { + editor = o + }) + ) runs(() => { pane4 = workspace.getPanes().filter(p => p !== pane1)[0] expect(workspace.getActivePane()).toBe(pane4) expect(pane4.items).toEqual([editor]) - expect(workspace.getCenter().paneContainer.root.children[0]).toBe(pane1) - expect(workspace.getCenter().paneContainer.root.children[1]).toBe(pane2) + expect(workspace.getCenter().paneContainer.root.children[0]).toBe( + pane1 + ) + expect(workspace.getCenter().paneContainer.root.children[1]).toBe( + pane2 + ) }) }) }) @@ -670,29 +832,68 @@ describe('Workspace', () => { describe('when an initialLine and initialColumn are specified', () => { it('moves the cursor to the indicated location', () => { - waitsForPromise(() => workspace.open('a', {initialLine: 1, initialColumn: 5})) + waitsForPromise(() => + workspace.open('a', { initialLine: 1, initialColumn: 5 }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 5])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([1, 5]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: 2, initialColumn: 4})) + waitsForPromise(() => + workspace.open('a', { initialLine: 2, initialColumn: 4 }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([2, 4])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([2, 4]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: 0, initialColumn: 0})) + waitsForPromise(() => + workspace.open('a', { initialLine: 0, initialColumn: 0 }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([0, 0]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: NaN, initialColumn: 4})) + waitsForPromise(() => + workspace.open('a', { initialLine: NaN, initialColumn: 4 }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 4])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([0, 4]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: 2, initialColumn: NaN})) + waitsForPromise(() => + workspace.open('a', { initialLine: 2, initialColumn: NaN }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([2, 0])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([2, 0]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: Infinity, initialColumn: Infinity})) + waitsForPromise(() => + workspace.open('a', { + initialLine: Infinity, + initialColumn: Infinity + }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([2, 11])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([2, 11]) + ) }) }) @@ -701,7 +902,9 @@ describe('Workspace', () => { spyOn(fs, 'getSizeSync').andReturn(size * 1048577) let selectedButtonIndex = 1 // cancel - atom.applicationDelegate.confirm.andCallFake((options, callback) => callback(selectedButtonIndex)) + atom.applicationDelegate.confirm.andCallFake((options, callback) => + callback(selectedButtonIndex) + ) let editor = await workspace.open('sample.js') if (shouldPrompt) { @@ -739,12 +942,12 @@ describe('Workspace', () => { it('returns the resource returned by the custom opener', () => { const fooOpener = (pathToOpen, options) => { if (pathToOpen != null ? pathToOpen.match(/\.foo/) : undefined) { - return {foo: pathToOpen, options} + return { foo: pathToOpen, options } } } - const barOpener = (pathToOpen) => { + const barOpener = pathToOpen => { if (pathToOpen != null ? pathToOpen.match(/^bar:\/\//) : undefined) { - return {bar: pathToOpen} + return { bar: pathToOpen } } } workspace.addOpener(fooOpener) @@ -752,29 +955,51 @@ describe('Workspace', () => { waitsForPromise(() => { const pathToOpen = atom.project.getDirectories()[0].resolve('a.foo') - return workspace.open(pathToOpen, {hey: 'there'}).then(item => expect(item).toEqual({foo: pathToOpen, options: {hey: 'there'}})) + return workspace.open(pathToOpen, { hey: 'there' }).then(item => + expect(item).toEqual({ + foo: pathToOpen, + options: { hey: 'there' } + }) + ) }) waitsForPromise(() => - workspace.open('bar://baz').then(item => expect(item).toEqual({bar: 'bar://baz'}))) + workspace + .open('bar://baz') + .then(item => expect(item).toEqual({ bar: 'bar://baz' })) + ) }) }) it("adds the file to the application's recent documents list", () => { - if (process.platform !== 'darwin') { return } // Feature only supported on macOS + if (process.platform !== 'darwin') { + return + } // Feature only supported on macOS spyOn(atom.applicationDelegate, 'addRecentDocument') waitsForPromise(() => workspace.open()) - runs(() => expect(atom.applicationDelegate.addRecentDocument).not.toHaveBeenCalled()) + runs(() => + expect( + atom.applicationDelegate.addRecentDocument + ).not.toHaveBeenCalled() + ) waitsForPromise(() => workspace.open('something://a/url')) - runs(() => expect(atom.applicationDelegate.addRecentDocument).not.toHaveBeenCalled()) + runs(() => + expect( + atom.applicationDelegate.addRecentDocument + ).not.toHaveBeenCalled() + ) waitsForPromise(() => workspace.open(__filename)) - runs(() => expect(atom.applicationDelegate.addRecentDocument).toHaveBeenCalledWith(__filename)) + runs(() => + expect(atom.applicationDelegate.addRecentDocument).toHaveBeenCalledWith( + __filename + ) + ) }) it('notifies ::onDidAddTextEditor observers', () => { @@ -783,14 +1008,24 @@ describe('Workspace', () => { workspace.onDidAddTextEditor(newEditorHandler) let editor = null - waitsForPromise(() => workspace.open(absolutePath).then(e => { editor = e })) + waitsForPromise(() => + workspace.open(absolutePath).then(e => { + editor = e + }) + ) - runs(() => expect(newEditorHandler.argsForCall[0][0].textEditor).toBe(editor)) + runs(() => + expect(newEditorHandler.argsForCall[0][0].textEditor).toBe(editor) + ) }) describe('when there is an error opening the file', () => { let notificationSpy = null - beforeEach(() => atom.notifications.onDidAddNotification(notificationSpy = jasmine.createSpy())) + beforeEach(() => + atom.notifications.onDidAddNotification( + (notificationSpy = jasmine.createSpy()) + ) + ) describe('when a file does not exist', () => { it('creates an empty buffer for the specified path', () => { @@ -881,9 +1116,11 @@ describe('Workspace', () => { ) it('rejects the promise', () => { - waitsFor((done) => { + waitsFor(done => { workspace.open('file1').catch(error => { - expect(error.message).toBe('I dont even know what is happening right now!!') + expect(error.message).toBe( + 'I dont even know what is happening right now!!' + ) done() }) }) @@ -897,7 +1134,7 @@ describe('Workspace', () => { let pane = null waitsForPromise(() => - atom.workspace.open('sample.js', {pending: true}).then(o => { + atom.workspace.open('sample.js', { pending: true }).then(o => { editor = o pane = atom.workspace.getActivePane() }) @@ -917,11 +1154,15 @@ describe('Workspace', () => { let editor2 = null waitsForPromise(() => - atom.workspace.open('sample.txt').then(o => { editor1 = o }) + atom.workspace.open('sample.txt').then(o => { + editor1 = o + }) ) waitsForPromise(() => - atom.workspace.open('sample2.txt', {pending: true}).then(o => { editor2 = o }) + atom.workspace.open('sample2.txt', { pending: true }).then(o => { + editor2 = o + }) ) runs(() => { @@ -942,11 +1183,13 @@ describe('Workspace', () => { let rightPane = null waitsForPromise(() => - atom.workspace.open('sample.js', {pending: true, split: 'right'}).then(o => { - editor1 = o - rightPane = atom.workspace.getActivePane() - spyOn(rightPane, 'destroy').andCallThrough() - }) + atom.workspace + .open('sample.js', { pending: true, split: 'right' }) + .then(o => { + editor1 = o + rightPane = atom.workspace.getActivePane() + spyOn(rightPane, 'destroy').andCallThrough() + }) ) runs(() => { @@ -957,7 +1200,9 @@ describe('Workspace', () => { }) waitsForPromise(() => - atom.workspace.open('sample.txt', {pending: true}).then(o => { editor2 = o }) + atom.workspace.open('sample.txt', { pending: true }).then(o => { + editor2 = o + }) ) runs(() => { @@ -967,15 +1212,19 @@ describe('Workspace', () => { }) }) - describe('when opening an editor with a buffer that isn\'t part of the project', () => { + describe("when opening an editor with a buffer that isn't part of the project", () => { it('adds the buffer to the project', async () => { const buffer = new TextBuffer() - const editor = new TextEditor({buffer}) + const editor = new TextEditor({ buffer }) await atom.workspace.open(editor) - expect(atom.project.getBuffers().map(buffer => buffer.id)).toContain(buffer.id) - expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar') + expect(atom.project.getBuffers().map(buffer => buffer.id)).toContain( + buffer.id + ) + expect(buffer.getLanguageMode().getLanguageId()).toBe( + 'text.plain.null-grammar' + ) }) }) }) @@ -985,21 +1234,42 @@ describe('Workspace', () => { const uri = 'atom://test-pane-for-item' const item = { element: document.createElement('div'), - getURI () { return uri } + getURI () { + return uri + } } atom.workspace.getActivePane().activateItem(item) - expect(atom.workspace.paneForItem(item)).toBe(atom.workspace.getCenter().getActivePane()) - expect(atom.workspace.paneContainerForItem(item)).toBe(atom.workspace.getCenter()) - expect(atom.workspace.paneForURI(uri)).toBe(atom.workspace.getCenter().getActivePane()) - expect(atom.workspace.paneContainerForURI(uri)).toBe(atom.workspace.getCenter()) + expect(atom.workspace.paneForItem(item)).toBe( + atom.workspace.getCenter().getActivePane() + ) + expect(atom.workspace.paneContainerForItem(item)).toBe( + atom.workspace.getCenter() + ) + expect(atom.workspace.paneForURI(uri)).toBe( + atom.workspace.getCenter().getActivePane() + ) + expect(atom.workspace.paneContainerForURI(uri)).toBe( + atom.workspace.getCenter() + ) atom.workspace.getActivePane().destroyActiveItem() - atom.workspace.getLeftDock().getActivePane().activateItem(item) - expect(atom.workspace.paneForItem(item)).toBe(atom.workspace.getLeftDock().getActivePane()) - expect(atom.workspace.paneContainerForItem(item)).toBe(atom.workspace.getLeftDock()) - expect(atom.workspace.paneForURI(uri)).toBe(atom.workspace.getLeftDock().getActivePane()) - expect(atom.workspace.paneContainerForURI(uri)).toBe(atom.workspace.getLeftDock()) + atom.workspace + .getLeftDock() + .getActivePane() + .activateItem(item) + expect(atom.workspace.paneForItem(item)).toBe( + atom.workspace.getLeftDock().getActivePane() + ) + expect(atom.workspace.paneContainerForItem(item)).toBe( + atom.workspace.getLeftDock() + ) + expect(atom.workspace.paneForURI(uri)).toBe( + atom.workspace.getLeftDock().getActivePane() + ) + expect(atom.workspace.paneContainerForURI(uri)).toBe( + atom.workspace.getLeftDock() + ) }) }) @@ -1061,13 +1331,21 @@ describe('Workspace', () => { describe('when the location resolves to a dock', () => { it('adds or shows the item and its dock if it is not currently visible, and otherwise hides the containing dock', async () => { const item1 = { - getDefaultLocation () { return 'left' }, - getElement () { return (this.element = document.createElement('div')) } + getDefaultLocation () { + return 'left' + }, + getElement () { + return (this.element = document.createElement('div')) + } } const item2 = { - getDefaultLocation () { return 'left' }, - getElement () { return (this.element = document.createElement('div')) } + getDefaultLocation () { + return 'left' + }, + getElement () { + return (this.element = document.createElement('div')) + } } const dock = workspace.getLeftDock() @@ -1098,13 +1376,21 @@ describe('Workspace', () => { describe('when the location resolves to the center', () => { it('adds or shows the item if it is not currently the active pane item, and otherwise removes the item', async () => { const item1 = { - getDefaultLocation () { return 'center' }, - getElement () { return (this.element = document.createElement('div')) } + getDefaultLocation () { + return 'center' + }, + getElement () { + return (this.element = document.createElement('div')) + } } const item2 = { - getDefaultLocation () { return 'center' }, - getElement () { return (this.element = document.createElement('div')) } + getDefaultLocation () { + return 'center' + }, + getElement () { + return (this.element = document.createElement('div')) + } } expect(workspace.getActivePaneItem()).toBeUndefined() @@ -1124,43 +1410,45 @@ describe('Workspace', () => { describe('active pane containers', () => { it('maintains the active pane and item globally across active pane containers', () => { const leftDock = workspace.getLeftDock() - const leftItem1 = {element: document.createElement('div')} - const leftItem2 = {element: document.createElement('div')} - const leftItem3 = {element: document.createElement('div')} + const leftItem1 = { element: document.createElement('div') } + const leftItem2 = { element: document.createElement('div') } + const leftItem3 = { element: document.createElement('div') } const leftPane1 = leftDock.getActivePane() leftPane1.addItems([leftItem1, leftItem2]) - const leftPane2 = leftPane1.splitDown({items: [leftItem3]}) + const leftPane2 = leftPane1.splitDown({ items: [leftItem3] }) const rightDock = workspace.getRightDock() - const rightItem1 = {element: document.createElement('div')} - const rightItem2 = {element: document.createElement('div')} - const rightItem3 = {element: document.createElement('div')} + const rightItem1 = { element: document.createElement('div') } + const rightItem2 = { element: document.createElement('div') } + const rightItem3 = { element: document.createElement('div') } const rightPane1 = rightDock.getActivePane() rightPane1.addItems([rightItem1, rightItem2]) - const rightPane2 = rightPane1.splitDown({items: [rightItem3]}) + const rightPane2 = rightPane1.splitDown({ items: [rightItem3] }) const bottomDock = workspace.getBottomDock() - const bottomItem1 = {element: document.createElement('div')} - const bottomItem2 = {element: document.createElement('div')} - const bottomItem3 = {element: document.createElement('div')} + const bottomItem1 = { element: document.createElement('div') } + const bottomItem2 = { element: document.createElement('div') } + const bottomItem3 = { element: document.createElement('div') } const bottomPane1 = bottomDock.getActivePane() bottomPane1.addItems([bottomItem1, bottomItem2]) - const bottomPane2 = bottomPane1.splitDown({items: [bottomItem3]}) + const bottomPane2 = bottomPane1.splitDown({ items: [bottomItem3] }) const center = workspace.getCenter() - const centerItem1 = {element: document.createElement('div')} - const centerItem2 = {element: document.createElement('div')} - const centerItem3 = {element: document.createElement('div')} + const centerItem1 = { element: document.createElement('div') } + const centerItem2 = { element: document.createElement('div') } + const centerItem3 = { element: document.createElement('div') } const centerPane1 = center.getActivePane() centerPane1.addItems([centerItem1, centerItem2]) - const centerPane2 = centerPane1.splitDown({items: [centerItem3]}) + const centerPane2 = centerPane1.splitDown({ items: [centerItem3] }) const activePaneContainers = [] const activePanes = [] const activeItems = [] - workspace.onDidChangeActivePaneContainer((container) => activePaneContainers.push(container)) - workspace.onDidChangeActivePane((pane) => activePanes.push(pane)) - workspace.onDidChangeActivePaneItem((item) => activeItems.push(item)) + workspace.onDidChangeActivePaneContainer(container => + activePaneContainers.push(container) + ) + workspace.onDidChangeActivePane(pane => activePanes.push(pane)) + workspace.onDidChangeActivePaneItem(item => activeItems.push(item)) function clearEvents () { activePaneContainers.length = 0 activePanes.length = 0 @@ -1255,11 +1543,18 @@ describe('Workspace', () => { describe('::onDidStopChangingActivePaneItem()', () => { it('invokes observers when the active item of the active pane stops changing', () => { const pane1 = atom.workspace.getCenter().getActivePane() - const pane2 = pane1.splitRight({items: [document.createElement('div'), document.createElement('div')]}); - atom.workspace.getLeftDock().getActivePane().addItem(document.createElement('div')) + const pane2 = pane1.splitRight({ + items: [document.createElement('div'), document.createElement('div')] + }) + atom.workspace + .getLeftDock() + .getActivePane() + .addItem(document.createElement('div')) emittedItems = [] - atom.workspace.onDidStopChangingActivePaneItem(item => emittedItems.push(item)) + atom.workspace.onDidStopChangingActivePaneItem(item => + emittedItems.push(item) + ) pane2.activateNextItem() pane2.activateNextItem() @@ -1267,7 +1562,9 @@ describe('Workspace', () => { atom.workspace.getLeftDock().activate() advanceClock(100) - expect(emittedItems).toEqual([atom.workspace.getLeftDock().getActivePaneItem()]) + expect(emittedItems).toEqual([ + atom.workspace.getLeftDock().getActivePaneItem() + ]) }) }) @@ -1281,15 +1578,23 @@ describe('Workspace', () => { const coffeeScriptGrammarUsed = jasmine.createSpy('coffeescript') atom.packages.triggerDeferredActivationHooks() - atom.packages.onDidTriggerActivationHook('language-javascript:grammar-used', () => { - atom.workspace.observeTextEditors(observeTextEditorsSpy) - javascriptGrammarUsed() - }) - atom.packages.onDidTriggerActivationHook('language-coffee-script:grammar-used', coffeeScriptGrammarUsed) + atom.packages.onDidTriggerActivationHook( + 'language-javascript:grammar-used', + () => { + atom.workspace.observeTextEditors(observeTextEditorsSpy) + javascriptGrammarUsed() + } + ) + atom.packages.onDidTriggerActivationHook( + 'language-coffee-script:grammar-used', + coffeeScriptGrammarUsed + ) expect(javascriptGrammarUsed).not.toHaveBeenCalled() expect(observeTextEditorsSpy).not.toHaveBeenCalled() - const editor = await atom.workspace.open('sample.js', {autoIndent: false}) + const editor = await atom.workspace.open('sample.js', { + autoIndent: false + }) expect(javascriptGrammarUsed).toHaveBeenCalled() expect(observeTextEditorsSpy.callCount).toBe(1) @@ -1309,15 +1614,23 @@ describe('Workspace', () => { const coffeeScriptGrammarUsed = jasmine.createSpy('coffeescript') atom.packages.triggerDeferredActivationHooks() - atom.packages.onDidTriggerActivationHook('source.js:root-scope-used', () => { - atom.workspace.observeTextEditors(observeTextEditorsSpy) - javascriptGrammarUsed() - }) - atom.packages.onDidTriggerActivationHook('source.coffee:root-scope-used', coffeeScriptGrammarUsed) + atom.packages.onDidTriggerActivationHook( + 'source.js:root-scope-used', + () => { + atom.workspace.observeTextEditors(observeTextEditorsSpy) + javascriptGrammarUsed() + } + ) + atom.packages.onDidTriggerActivationHook( + 'source.coffee:root-scope-used', + coffeeScriptGrammarUsed + ) expect(javascriptGrammarUsed).not.toHaveBeenCalled() expect(observeTextEditorsSpy).not.toHaveBeenCalled() - const editor = await atom.workspace.open('sample.js', {autoIndent: false}) + const editor = await atom.workspace.open('sample.js', { + autoIndent: false + }) expect(javascriptGrammarUsed).toHaveBeenCalled() expect(observeTextEditorsSpy.callCount).toBe(1) @@ -1331,11 +1644,13 @@ describe('Workspace', () => { it("opens the uri associated with the last closed pane that isn't currently open", () => { const pane = workspace.getActivePane() waitsForPromise(() => - workspace.open('a').then(() => - workspace.open('b').then(() => - workspace.open('file1').then(() => workspace.open()) + workspace + .open('a') + .then(() => + workspace + .open('b') + .then(() => workspace.open('file1').then(() => workspace.open())) ) - ) ) runs(() => { @@ -1353,11 +1668,17 @@ describe('Workspace', () => { expect(workspace.getActivePaneItem().getURI()).not.toBeUndefined() // destroy all items - expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('file1')) + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('file1') + ) pane.destroyActiveItem() - expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('b')) + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('b') + ) pane.destroyActiveItem() - expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('a')) + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('a') + ) pane.destroyActiveItem() // reopens items with uris @@ -1366,16 +1687,28 @@ describe('Workspace', () => { waitsForPromise(() => workspace.reopenItem()) - runs(() => expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('a'))) + runs(() => + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('a') + ) + ) // does not reopen items that are already open waitsForPromise(() => workspace.open('b')) - runs(() => expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('b'))) + runs(() => + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('b') + ) + ) waitsForPromise(() => workspace.reopenItem()) - runs(() => expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('file1'))) + runs(() => + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('file1') + ) + ) }) }) @@ -1431,14 +1764,16 @@ describe('Workspace', () => { describe('::openLicense()', () => { it('opens the license as plain-text in a buffer', () => { waitsForPromise(() => workspace.openLicense()) - runs(() => expect(workspace.getActivePaneItem().getText()).toMatch(/Copyright/)) + runs(() => + expect(workspace.getActivePaneItem().getText()).toMatch(/Copyright/) + ) }) }) describe('::isTextEditor(obj)', () => { it('returns true when the passed object is an instance of `TextEditor`', () => { expect(workspace.isTextEditor(new TextEditor())).toBe(true) - expect(workspace.isTextEditor({getText: () => null})).toBe(false) + expect(workspace.isTextEditor({ getText: () => null })).toBe(false) expect(workspace.isTextEditor(null)).toBe(false) expect(workspace.isTextEditor(undefined)).toBe(false) }) @@ -1509,12 +1844,15 @@ describe('Workspace', () => { workspace.observeActiveTextEditor(editor => observed.push(editor)) const editorAddedAfterRegisteringObserver = new TextEditor() - const nonEditorItemAddedAfterRegisteringObserver = document.createElement('div') + const nonEditorItemAddedAfterRegisteringObserver = document.createElement( + 'div' + ) pane.activateItem(editorAddedAfterRegisteringObserver) - expect(observed).toEqual( - [activeEditorBeforeRegisteringObserver, editorAddedAfterRegisteringObserver] - ) + expect(observed).toEqual([ + activeEditorBeforeRegisteringObserver, + editorAddedAfterRegisteringObserver + ]) }) }) @@ -1602,7 +1940,7 @@ describe('Workspace', () => { atom.grammars.assignLanguageMode(editor, 'source.js') expect(editor.getGrammar().name).toBe('JavaScript') - workspace.getActivePane().splitRight({copyActiveItem: true}) + workspace.getActivePane().splitRight({ copyActiveItem: true }) const newEditor = workspace.getActiveTextEditor() expect(newEditor).not.toBe(editor) expect(newEditor.getGrammar().name).toBe('JavaScript') @@ -1612,36 +1950,45 @@ describe('Workspace', () => { it('stores the active grammars used by all the open editors', () => { waitsForPromise(() => atom.packages.activatePackage('language-javascript')) - waitsForPromise(() => atom.packages.activatePackage('language-coffee-script')) + waitsForPromise(() => + atom.packages.activatePackage('language-coffee-script') + ) waitsForPromise(() => atom.packages.activatePackage('language-todo')) waitsForPromise(() => atom.workspace.open('sample.coffee')) runs(() => { - atom.workspace.getActiveTextEditor().setText(dedent ` + atom.workspace.getActiveTextEditor().setText(dedent` i = /test/; #FIXME\ `) - const atom2 = new AtomEnvironment({applicationDelegate: atom.applicationDelegate}) + const atom2 = new AtomEnvironment({ + applicationDelegate: atom.applicationDelegate + }) atom2.initialize({ 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.packages.loadPackage('language-javascript') atom2.packages.loadPackage('language-coffee-script') atom2.packages.loadPackage('language-todo') atom2.project.deserialize(atom.project.serialize()) - atom2.workspace.deserialize(atom.workspace.serialize(), atom2.deserializers) + atom2.workspace.deserialize( + atom.workspace.serialize(), + atom2.deserializers + ) - expect(atom2.grammars.getGrammars().map(grammar => grammar.scopeName).sort()).toEqual([ + expect( + atom2.grammars + .getGrammars() + .map(grammar => grammar.scopeName) + .sort() + ).toEqual([ 'source.coffee', 'source.js', 'source.js.regexp', @@ -1658,7 +2005,10 @@ describe('Workspace', () => { describe('document.title', () => { describe('when there is no item open', () => { - it('sets the title to the project path', () => expect(document.title).toMatch(escapeStringRegex(fs.tildify(atom.project.getPaths()[0])))) + it('sets the title to the project path', () => + expect(document.title).toMatch( + escapeStringRegex(fs.tildify(atom.project.getPaths()[0])) + )) it("sets the title to 'untitled' if there is no project path", () => { atom.project.setPaths([]) @@ -1675,16 +2025,24 @@ describe('Workspace', () => { it("sets the title to the pane item's title plus the item's path", () => { const item = atom.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(path.dirname(item.getPath()))) - expect(document.title).toMatch(new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(path.dirname(item.getPath())) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`) + ) }) describe('when the title of the active pane item changes', () => { it("updates the window title based on the item's new title", () => { const editor = atom.workspace.getActivePaneItem() editor.buffer.setPath(path.join(temp.dir, 'hi')) - const pathEscaped = fs.tildify(escapeStringRegex(path.dirname(editor.getPath()))) - expect(document.title).toMatch(new RegExp(`^${editor.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(path.dirname(editor.getPath())) + ) + expect(document.title).toMatch( + new RegExp(`^${editor.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1692,8 +2050,12 @@ describe('Workspace', () => { it("updates the title to the new item's title plus the project path", () => { atom.workspace.getActivePane().activateNextItem() const item = atom.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(path.dirname(item.getPath()))) - expect(document.title).toMatch(new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(path.dirname(item.getPath())) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1709,15 +2071,17 @@ describe('Workspace', () => { }) describe('when the active pane item is inside a project path', () => { - beforeEach(() => - waitsForPromise(() => atom.workspace.open('b')) - ) + beforeEach(() => waitsForPromise(() => atom.workspace.open('b'))) describe('when there is an active pane item', () => { it("sets the title to the pane item's title plus the project path", () => { const item = atom.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1725,8 +2089,12 @@ describe('Workspace', () => { it("updates the window title based on the item's new title", () => { const editor = atom.workspace.getActivePaneItem() editor.buffer.setPath(path.join(atom.project.getPaths()[0], 'hi')) - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${editor.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp(`^${editor.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1734,8 +2102,12 @@ describe('Workspace', () => { it("updates the title to the new item's title plus the project path", () => { atom.workspace.getActivePane().activateNextItem() const item = atom.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1743,7 +2115,9 @@ describe('Workspace', () => { it("updates the title to the project's first path", () => { atom.workspace.getActivePane().destroy() expect(atom.workspace.getActivePaneItem()).toBeUndefined() - expect(document.title).toMatch(escapeStringRegex(fs.tildify(atom.project.getPaths()[0]))) + expect(document.title).toMatch( + escapeStringRegex(fs.tildify(atom.project.getPaths()[0])) + ) }) }) @@ -1764,25 +2138,33 @@ describe('Workspace', () => { it("updates the title to contain the project's path", () => { document.title = null - const atom2 = new AtomEnvironment({applicationDelegate: atom.applicationDelegate}) + const atom2 = new AtomEnvironment({ + applicationDelegate: atom.applicationDelegate + }) atom2.initialize({ 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') + }) }) - waitsForPromise(() => atom2.project.deserialize(atom.project.serialize())) + waitsForPromise(() => + atom2.project.deserialize(atom.project.serialize()) + ) runs(() => { - atom2.workspace.deserialize(atom.workspace.serialize(), atom2.deserializers) + atom2.workspace.deserialize( + atom.workspace.serialize(), + atom2.deserializers + ) const item = atom2.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${item.getLongTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getLongTitle()} \\u2014 ${pathEscaped}`) + ) atom2.destroy() }) @@ -1798,7 +2180,7 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.open('a')) waitsForPromise(() => atom.workspace.open('b')) runs(() => { - [item1, item2] = atom.workspace.getPaneItems() + ;[item1, item2] = atom.workspace.getPaneItems() }) }) @@ -1832,31 +2214,46 @@ describe('Workspace', () => { // Don't use ES6 classes because then we'll have to call `super()` which we can't do with // HTMLElement - function TestItemElement () { this.constructor = TestItemElement } - function Ctor () { this.constructor = TestItemElement } + function TestItemElement () { + this.constructor = TestItemElement + } + function Ctor () { + this.constructor = TestItemElement + } Ctor.prototype = HTMLElement.prototype TestItemElement.prototype = new Ctor() TestItemElement.__super__ = HTMLElement.prototype - TestItemElement.prototype.initialize = function (model) { this.model = model; return this } - TestItemElement.prototype.getModel = function () { return this.model } + TestItemElement.prototype.initialize = function (model) { + this.model = model + return this + } + TestItemElement.prototype.getModel = function () { + return this.model + } beforeEach(() => - atom.views.addViewProvider(TestItem, model => new TestItemElement().initialize(model)) + atom.views.addViewProvider(TestItem, model => + new TestItemElement().initialize(model) + ) ) describe('::addLeftPanel(model)', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getLeftPanels().length).toBe(0) - atom.workspace.panelContainers.left.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.left.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addLeftPanel({item: model}) + const panel = atom.workspace.addLeftPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getLeftPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getLeftPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1866,15 +2263,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getRightPanels().length).toBe(0) - atom.workspace.panelContainers.right.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.right.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addRightPanel({item: model}) + const panel = atom.workspace.addRightPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getRightPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getRightPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1884,15 +2285,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getTopPanels().length).toBe(0) - atom.workspace.panelContainers.top.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.top.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addTopPanel({item: model}) + const panel = atom.workspace.addTopPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getTopPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getTopPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1902,15 +2307,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getBottomPanels().length).toBe(0) - atom.workspace.panelContainers.bottom.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.bottom.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addBottomPanel({item: model}) + const panel = atom.workspace.addBottomPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getBottomPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getBottomPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1920,15 +2329,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getHeaderPanels().length).toBe(0) - atom.workspace.panelContainers.header.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.header.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addHeaderPanel({item: model}) + const panel = atom.workspace.addHeaderPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getHeaderPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getHeaderPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1938,15 +2351,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getFooterPanels().length).toBe(0) - atom.workspace.panelContainers.footer.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.footer.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addFooterPanel({item: model}) + const panel = atom.workspace.addFooterPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getFooterPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getFooterPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1956,15 +2373,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getModalPanels().length).toBe(0) - atom.workspace.panelContainers.modal.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.modal.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addModalPanel({item: model}) + const panel = atom.workspace.addModalPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getModalPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getModalPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1973,7 +2394,7 @@ describe('Workspace', () => { describe('::panelForItem(item)', () => { it('returns the panel associated with the item', () => { const item = new TestItem() - const panel = atom.workspace.addLeftPanel({item}) + const panel = atom.workspace.addLeftPanel({ item }) const itemWithNoPanel = new TestItem() @@ -1989,13 +2410,17 @@ describe('Workspace', () => { const results = [] waitsForPromise(() => atom.workspace.scan( - /(a)+/, {leadingContextLineCount: 1, trailingContextLineCount: 1}, - result => results.push(result)) + /(a)+/, + { leadingContextLineCount: 1, trailingContextLineCount: 1 }, + result => results.push(result) + ) ) runs(() => { expect(results).toHaveLength(3) - expect(results[0].filePath).toBe(atom.project.getDirectories()[0].resolve('a')) + expect(results[0].filePath).toBe( + atom.project.getDirectories()[0].resolve('a') + ) expect(results[0].matches).toHaveLength(3) expect(results[0].matches[0]).toEqual({ matchText: 'aaa', @@ -2010,13 +2435,17 @@ describe('Workspace', () => { it('works with with escaped literals (like $ and ^)', () => { const results = [] - waitsForPromise(() => atom.workspace.scan( - /\$\w+/, {leadingContextLineCount: 1, trailingContextLineCount: 1}, - result => results.push(result))) + waitsForPromise(() => + atom.workspace.scan( + /\$\w+/, + { leadingContextLineCount: 1, trailingContextLineCount: 1 }, + result => results.push(result) + ) + ) runs(() => { expect(results.length).toBe(1) - const {filePath, matches} = results[0] + const { filePath, matches } = results[0] expect(filePath).toBe(atom.project.getDirectories()[0].resolve('a')) expect(matches).toHaveLength(1) expect(matches[0]).toEqual({ @@ -2064,7 +2493,9 @@ describe('Workspace', () => { it('ignores case if the regex includes the `i` flag', () => { const results = [] - waitsForPromise(() => atom.workspace.scan(/DOLLAR/i, result => results.push(result))) + waitsForPromise(() => + atom.workspace.scan(/DOLLAR/i, result => results.push(result)) + ) runs(() => expect(results).toHaveLength(1)) }) @@ -2074,7 +2505,12 @@ describe('Workspace', () => { let ignoredPath beforeEach(() => { - const sourceProjectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir') + const sourceProjectPath = path.join( + __dirname, + 'fixtures', + 'git', + 'working-dir' + ) projectPath = path.join(temp.mkdirSync('atom')) const writerStream = fstream.Writer(projectPath) @@ -2086,7 +2522,10 @@ describe('Workspace', () => { }) runs(() => { - fs.rename(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) + fs.rename( + path.join(projectPath, 'git.git'), + path.join(projectPath, '.git') + ) ignoredPath = path.join(projectPath, 'ignored.txt') fs.writeFileSync(ignoredPath, 'this match should not be included') }) @@ -2119,10 +2558,14 @@ describe('Workspace', () => { const paths = [] let matches = [] waitsForPromise(() => - atom.workspace.scan(/aaa/, {paths: [`a-dir${path.sep}`]}, result => { - paths.push(result.filePath) - matches = matches.concat(result.matches) - }) + atom.workspace.scan( + /aaa/, + { paths: [`a-dir${path.sep}`] }, + result => { + paths.push(result.filePath) + matches = matches.concat(result.matches) + } + ) ) runs(() => { @@ -2177,11 +2620,16 @@ describe('Workspace', () => { }) ) - waitsForPromise(() => atom.workspace.scan(/a|Elephant/, result => results.push(result))) + waitsForPromise(() => + atom.workspace.scan(/a|Elephant/, result => results.push(result)) + ) runs(() => { expect(results).toHaveLength(3) - const resultForA = _.find(results, ({filePath}) => path.basename(filePath) === 'a') + const resultForA = _.find( + results, + ({ filePath }) => path.basename(filePath) === 'a' + ) expect(resultForA.matches).toHaveLength(1) expect(resultForA.matches[0].matchText).toBe('Elephant') }) @@ -2198,7 +2646,9 @@ describe('Workspace', () => { }) ) - waitsForPromise(() => atom.workspace.scan(/Elephant/, result => results.push(result))) + waitsForPromise(() => + atom.workspace.scan(/Elephant/, result => results.push(result)) + ) runs(() => expect(results).toHaveLength(0)) }) @@ -2225,7 +2675,9 @@ describe('Workspace', () => { it("searches matching files in all of the project's root directories", () => { const resultPaths = [] waitsForPromise(() => - atom.workspace.scan(/aaaa/, ({filePath}) => resultPaths.push(filePath)) + atom.workspace.scan(/aaaa/, ({ filePath }) => + resultPaths.push(filePath) + ) ) runs(() => expect(resultPaths.sort()).toEqual([file1, file2].sort())) @@ -2236,7 +2688,7 @@ describe('Workspace', () => { waitsForPromise(() => { const resultPaths = [] return atom.workspace - .scan(/aaaa/, {paths: ['dir']}, ({filePath}) => { + .scan(/aaaa/, { paths: ['dir'] }, ({ filePath }) => { if (!resultPaths.includes(filePath)) { resultPaths.push(filePath) } @@ -2247,33 +2699,45 @@ describe('Workspace', () => { waitsForPromise(() => { const resultPaths = [] return atom.workspace - .scan(/aaaa/, {paths: [path.join('dir', 'a-dir')]}, ({filePath}) => { - if (!resultPaths.includes(filePath)) { - resultPaths.push(filePath) + .scan( + /aaaa/, + { paths: [path.join('dir', 'a-dir')] }, + ({ filePath }) => { + if (!resultPaths.includes(filePath)) { + resultPaths.push(filePath) + } } - }) + ) .then(() => expect(resultPaths).toEqual([file1])) }) waitsForPromise(() => { const resultPaths = [] return atom.workspace - .scan(/aaaa/, {paths: [path.basename(dir2)]}, ({filePath}) => { - if (!resultPaths.includes(filePath)) { - resultPaths.push(filePath) + .scan( + /aaaa/, + { paths: [path.basename(dir2)] }, + ({ filePath }) => { + if (!resultPaths.includes(filePath)) { + resultPaths.push(filePath) + } } - }) + ) .then(() => expect(resultPaths).toEqual([file2])) }) waitsForPromise(() => { const resultPaths = [] return atom.workspace - .scan(/aaaa/, {paths: [path.join(path.basename(dir2), 'a-dir')]}, ({filePath}) => { - if (!resultPaths.includes(filePath)) { - resultPaths.push(filePath) + .scan( + /aaaa/, + { paths: [path.join(path.basename(dir2), 'a-dir')] }, + ({ filePath }) => { + if (!resultPaths.includes(filePath)) { + resultPaths.push(filePath) + } } - }) + ) .then(() => expect(resultPaths).toEqual([file2])) }) }) @@ -2310,13 +2774,19 @@ describe('Workspace', () => { beforeEach(() => { fakeSearch = null onFakeSearchCreated = null - atom.packages.serviceHub.provide('atom.directory-searcher', '0.1.0', { - canSearchDirectory (directory) { return directory.getPath() === dir1 }, - search (directory, regex, options) { - fakeSearch = new FakeSearch(options) - return fakeSearch + atom.packages.serviceHub.provide( + 'atom.directory-searcher', + '0.1.0', + { + canSearchDirectory (directory) { + return directory.getPath() === dir1 + }, + search (directory, regex, options) { + fakeSearch = new FakeSearch(options) + return fakeSearch + } } - }) + ) waitsFor(() => atom.workspace.directorySearchers.length > 0) }) @@ -2338,24 +2808,32 @@ describe('Workspace', () => { } onFakeSearchCreated = fakeSearch => { fakeSearch.options.didMatch(searchResult) - fakeSearch.options.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) + fakeSearch.options.didSearchPaths( + numPathsToPretendToSearchInCustomDirectorySearcher + ) fakeSearch.hoistedResolve() } const resultPaths = [] const onPathsSearched = jasmine.createSpy('onPathsSearched') waitsForPromise(() => - atom.workspace.scan(/aaaa/, {onPathsSearched}, ({filePath}) => resultPaths.push(filePath)) + atom.workspace.scan(/aaaa/, { onPathsSearched }, ({ filePath }) => + resultPaths.push(filePath) + ) ) runs(() => { - expect(resultPaths.sort()).toEqual([foreignFilePath, file2].sort()) + expect(resultPaths.sort()).toEqual( + [foreignFilePath, file2].sort() + ) // onPathsSearched should be called once by each DirectorySearcher. The order is not // guaranteed, so we can only verify the total number of paths searched is correct // after the second call. expect(onPathsSearched.callCount).toBe(2) expect(onPathsSearched.mostRecentCall.args[0]).toBe( - numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2) + numPathsToPretendToSearchInCustomDirectorySearcher + + numPathsSearchedInDir2 + ) }) }) @@ -2371,7 +2849,11 @@ describe('Workspace', () => { expect(fakeSearch.cancelled).toBe(true) }) - waitsForPromise(() => thenable.then(promiseResult => { resultOfPromiseSearch = promiseResult })) + waitsForPromise(() => + thenable.then(promiseResult => { + resultOfPromiseSearch = promiseResult + }) + ) runs(() => expect(resultOfPromiseSearch).toBe('cancelled')) }) @@ -2380,21 +2862,34 @@ describe('Workspace', () => { // This provider's search should be cancelled when the first provider fails let cancelableSearch let fakeSearch2 = null - atom.packages.serviceHub.provide('atom.directory-searcher', '0.1.0', { - canSearchDirectory (directory) { return directory.getPath() === dir2 }, - search (directory, regex, options) { - fakeSearch2 = new FakeSearch(options) - return fakeSearch2 + atom.packages.serviceHub.provide( + 'atom.directory-searcher', + '0.1.0', + { + canSearchDirectory (directory) { + return directory.getPath() === dir2 + }, + search (directory, regex, options) { + fakeSearch2 = new FakeSearch(options) + return fakeSearch2 + } } - }) + ) let didReject = false - const promise = cancelableSearch = atom.workspace.scan(/aaaa/, () => {}) + const promise = (cancelableSearch = atom.workspace.scan( + /aaaa/, + () => {} + )) waitsFor('fakeSearch to be defined', () => fakeSearch != null) runs(() => fakeSearch.hoistedReject()) - waitsForPromise(() => cancelableSearch.catch(() => { didReject = true })) + waitsForPromise(() => + cancelableSearch.catch(() => { + didReject = true + }) + ) waitsFor(done => promise.then(null, done)) @@ -2424,7 +2919,12 @@ describe('Workspace', () => { expect(fs.existsSync(missingPath)).toBeFalsy() waitsForPromise(() => - atom.workspace.replace(/items/gi, 'items', [missingPath], (result, error) => errors.push(error)) + atom.workspace.replace( + /items/gi, + 'items', + [missingPath], + (result, error) => errors.push(error) + ) ) runs(() => { @@ -2441,7 +2941,9 @@ describe('Workspace', () => { const results = [] waitsForPromise(() => - atom.workspace.replace(/items/gi, 'items', [filePath], result => results.push(result)) + atom.workspace.replace(/items/gi, 'items', [filePath], result => + results.push(result) + ) ) runs(() => { @@ -2457,7 +2959,9 @@ describe('Workspace', () => { const results = [] waitsForPromise(() => - atom.workspace.replace(/;$/gmi, 'items', [filePath], result => results.push(result)) + atom.workspace.replace(/;$/gim, 'items', [filePath], result => + results.push(result) + ) ) runs(() => { @@ -2471,17 +2975,26 @@ describe('Workspace', () => { describe('when a buffer is already open', () => { it('replaces properly and saves when not modified', () => { const filePath = path.join(projectDir, 'sample.js') - fs.copyFileSync(path.join(fixturesDir, 'sample.js'), path.join(projectDir, 'sample.js')) + fs.copyFileSync( + path.join(fixturesDir, 'sample.js'), + path.join(projectDir, 'sample.js') + ) let editor = null const results = [] - waitsForPromise(() => atom.workspace.open('sample.js').then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open('sample.js').then(o => { + editor = o + }) + ) runs(() => expect(editor.isModified()).toBeFalsy()) waitsForPromise(() => - atom.workspace.replace(/items/gi, 'items', [filePath], result => results.push(result)) + atom.workspace.replace(/items/gi, 'items', [filePath], result => + results.push(result) + ) ) runs(() => { @@ -2497,13 +3010,21 @@ describe('Workspace', () => { const filePath = path.join(projectDir, 'sample.js') const commentFilePath = path.join(projectDir, 'sample-with-comments.js') fs.copyFileSync(path.join(fixturesDir, 'sample.js'), filePath) - fs.copyFileSync(path.join(fixturesDir, 'sample-with-comments.js'), path.join(projectDir, 'sample-with-comments.js')) + fs.copyFileSync( + path.join(fixturesDir, 'sample-with-comments.js'), + path.join(projectDir, 'sample-with-comments.js') + ) const results = [] waitsForPromise(() => atom.workspace.open('sample-with-comments.js')) waitsForPromise(() => - atom.workspace.replace(/items/gi, 'items', [commentFilePath], result => results.push(result)) + atom.workspace.replace( + /items/gi, + 'items', + [commentFilePath], + result => results.push(result) + ) ) runs(() => { @@ -2519,7 +3040,11 @@ describe('Workspace', () => { let editor = null const results = [] - waitsForPromise(() => atom.workspace.open('sample.js').then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open('sample.js').then(o => { + editor = o + }) + ) runs(() => { editor.buffer.setTextInRange([[0, 0], [0, 0]], 'omg') @@ -2527,7 +3052,9 @@ describe('Workspace', () => { }) waitsForPromise(() => - atom.workspace.replace(/items/gi, 'okthen', [filePath], result => results.push(result)) + atom.workspace.replace(/items/gi, 'okthen', [filePath], result => + results.push(result) + ) ) runs(() => { @@ -2545,9 +3072,11 @@ describe('Workspace', () => { let editor, notificationSpy beforeEach(() => { - waitsForPromise(() => atom.workspace.open('sample.js').then(o => { - editor = o - })) + waitsForPromise(() => + atom.workspace.open('sample.js').then(o => { + editor = o + }) + ) notificationSpy = jasmine.createSpy('did-add-notification') atom.notifications.onDidAddNotification(notificationSpy) @@ -2562,8 +3091,12 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) @@ -2576,15 +3109,21 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) it('emits a warning notification when the user does not have permission', () => { spyOn(editor, 'save').andCallFake(() => { - const error = new Error("EACCES, permission denied '/Some/dir/and-a-file.js'") + const error = new Error( + "EACCES, permission denied '/Some/dir/and-a-file.js'" + ) error.code = 'EACCES' error.path = '/Some/dir/and-a-file.js' throw error @@ -2593,15 +3132,21 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) it('emits a warning notification when the operation is not permitted', () => { spyOn(editor, 'save').andCallFake(() => { - const error = new Error("EPERM, operation not permitted '/Some/dir/and-a-file.js'") + const error = new Error( + "EPERM, operation not permitted '/Some/dir/and-a-file.js'" + ) error.code = 'EPERM' error.path = '/Some/dir/and-a-file.js' throw error @@ -2610,15 +3155,21 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) it('emits a warning notification when the file is already open by another app', () => { spyOn(editor, 'save').andCallFake(() => { - const error = new Error("EBUSY, resource busy or locked '/Some/dir/and-a-file.js'") + const error = new Error( + "EBUSY, resource busy or locked '/Some/dir/and-a-file.js'" + ) error.code = 'EBUSY' error.path = '/Some/dir/and-a-file.js' throw error @@ -2627,15 +3178,21 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) it('emits a warning notification when the file system is read-only', () => { spyOn(editor, 'save').andCallFake(() => { - const error = new Error("EROFS, read-only file system '/Some/dir/and-a-file.js'") + const error = new Error( + "EROFS, read-only file system '/Some/dir/and-a-file.js'" + ) error.code = 'EROFS' error.path = '/Some/dir/and-a-file.js' throw error @@ -2644,8 +3201,12 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) @@ -2655,7 +3216,7 @@ describe('Workspace', () => { throw new Error('no one knows') }) - waitsForPromise({shouldReject: true}, () => + waitsForPromise({ shouldReject: true }, () => atom.workspace.saveActivePaneItem() ) }) @@ -2672,7 +3233,7 @@ describe('Workspace', () => { atom.config.set('core.destroyEmptyPanes', false) const pane1 = atom.workspace.getActivePane() - const pane2 = pane1.splitRight({copyActiveItem: true}) + const pane2 = pane1.splitRight({ copyActiveItem: true }) expect(atom.workspace.getCenter().getPanes().length).toBe(2) expect(pane2.getItems().length).toBe(1) @@ -2819,13 +3380,25 @@ describe('Workspace', () => { expect(workspace.getVisiblePaneContainers()).toEqual([center]) leftDock.show() - expect(workspace.getVisiblePaneContainers().sort()).toEqual([center, leftDock]) + expect(workspace.getVisiblePaneContainers().sort()).toEqual([ + center, + leftDock + ]) rightDock.show() - expect(workspace.getVisiblePaneContainers().sort()).toEqual([center, leftDock, rightDock]) + expect(workspace.getVisiblePaneContainers().sort()).toEqual([ + center, + leftDock, + rightDock + ]) bottomDock.show() - expect(workspace.getVisiblePaneContainers().sort()).toEqual([center, leftDock, rightDock, bottomDock]) + expect(workspace.getVisiblePaneContainers().sort()).toEqual([ + center, + leftDock, + rightDock, + bottomDock + ]) }) }) @@ -2835,7 +3408,7 @@ describe('Workspace', () => { atom.config.set('core.allowPendingPaneItems', false) waitsForPromise(() => - atom.workspace.open('sample.js', {pending: true}).then(() => { + atom.workspace.open('sample.js', { pending: true }).then(() => { pane = atom.workspace.getActivePane() }) ) @@ -2852,9 +3425,18 @@ describe('Workspace', () => { const rubyGrammarUsed = jasmine.createSpy('ruby grammar used') const cGrammarUsed = jasmine.createSpy('c grammar used') - atom.packages.onDidTriggerActivationHook('language-javascript:grammar-used', javascriptGrammarUsed) - atom.packages.onDidTriggerActivationHook('language-ruby:grammar-used', rubyGrammarUsed) - atom.packages.onDidTriggerActivationHook('language-c:grammar-used', cGrammarUsed) + atom.packages.onDidTriggerActivationHook( + 'language-javascript:grammar-used', + javascriptGrammarUsed + ) + atom.packages.onDidTriggerActivationHook( + 'language-ruby:grammar-used', + rubyGrammarUsed + ) + atom.packages.onDidTriggerActivationHook( + 'language-c:grammar-used', + cGrammarUsed + ) await atom.packages.activatePackage('language-ruby') await atom.packages.activatePackage('language-javascript') @@ -2865,12 +3447,18 @@ describe('Workspace', () => { expect(javascriptGrammarUsed).toHaveBeenCalled() // Hooks are triggered when changing existing editors grammars - atom.grammars.assignLanguageMode(atom.workspace.getActiveTextEditor(), 'source.c') + atom.grammars.assignLanguageMode( + atom.workspace.getActiveTextEditor(), + 'source.c' + ) expect(cGrammarUsed).toHaveBeenCalled() // Hooks are triggered when editors are added in other ways. - atom.workspace.getActivePane().splitRight({copyActiveItem: true}) - atom.grammars.assignLanguageMode(atom.workspace.getActiveTextEditor(), 'source.ruby') + atom.workspace.getActivePane().splitRight({ copyActiveItem: true }) + atom.grammars.assignLanguageMode( + atom.workspace.getActiveTextEditor(), + 'source.ruby' + ) expect(rubyGrammarUsed).toHaveBeenCalled() }) }) @@ -2927,7 +3515,10 @@ describe('Workspace', () => { const dockPane = atom.workspace.getRightDock().getActivePane() spyOn(workspace.itemLocationStore, 'save') centerPane.moveItemToPane(item, dockPane) - expect(workspace.itemLocationStore.save).toHaveBeenCalledWith(ITEM_URI, 'right') + expect(workspace.itemLocationStore.save).toHaveBeenCalledWith( + ITEM_URI, + 'right' + ) }) it("clears the location if it's the default", () => { From d7d6d0838f2066ec51dd41559e4b6eeba1adca77 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 09:55:30 +0100 Subject: [PATCH 2/8] Remove unused vars from specs --- spec/application-delegate-spec.js | 9 +- spec/atom-environment-spec.js | 9 +- spec/atom-paths-spec.js | 9 +- spec/command-installer-spec.js | 3 - spec/command-registry-spec.js | 9 +- spec/config-file-spec.js | 6 +- spec/dock-spec.js | 11 +- spec/git-repository-provider-spec.js | 2 +- spec/git-repository-spec.js | 11 +- spec/grammar-registry-spec.js | 11 +- spec/history-manager-spec.js | 10 +- spec/package-manager-spec.js | 2 +- spec/package-transpilation-registry-spec.js | 10 +- spec/pane-container-spec.js | 7 +- spec/pane-spec.js | 3 - spec/panel-spec.js | 2 +- spec/reopen-project-menu-manager-spec.js | 11 +- spec/state-store-spec.js | 9 +- spec/style-manager-spec.js | 2 +- spec/text-editor-component-spec.js | 188 +++++++++----------- spec/text-editor-element-spec.js | 9 +- spec/text-editor-registry-spec.js | 3 +- spec/text-editor-spec.js | 60 ++----- spec/text-mate-language-mode-spec.js | 11 +- spec/tree-sitter-language-mode-spec.js | 9 +- spec/update-process-env-spec.js | 10 +- spec/workspace-center-spec.js | 9 +- spec/workspace-element-spec.js | 12 +- spec/workspace-spec.js | 8 +- 29 files changed, 134 insertions(+), 321 deletions(-) diff --git a/spec/application-delegate-spec.js b/spec/application-delegate-spec.js index 97326aa24..abe86d92d 100644 --- a/spec/application-delegate-spec.js +++ b/spec/application-delegate-spec.js @@ -1,13 +1,6 @@ /** @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 () { diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index 8e5dd5dba..a032b8eb2 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -1,12 +1,9 @@ const { it, - fit, - ffit, beforeEach, afterEach, conditionPromise } = require('./async-spec-helpers') -const _ = require('underscore-plus') const fs = require('fs') const path = require('path') const temp = require('temp').track() @@ -74,7 +71,7 @@ describe('AtomEnvironment', () => { it('will open the dev tools when an error is triggered', async () => { try { - a + 1 + a + 1 // eslint-ignore-line no-unused-vars } catch (e) { window.onerror.call(window, e.toString(), 'abc', 2, 3, e) } @@ -442,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) @@ -455,7 +451,7 @@ 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]) @@ -657,7 +653,6 @@ 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 () {}, diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index 438154d72..b7644e7cd 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -1,13 +1,6 @@ /** @babel */ -import { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} from './async-spec-helpers' +import { it, beforeEach, afterEach } from './async-spec-helpers' import { app } from 'remote' import atomPaths from '../src/atom-paths' import fs from 'fs-plus' diff --git a/spec/command-installer-spec.js b/spec/command-installer-spec.js index 2afa715fe..fb114928f 100644 --- a/spec/command-installer-spec.js +++ b/spec/command-installer-spec.js @@ -3,9 +3,6 @@ const fs = require('fs-plus') const temp = require('temp').track() const { it, - fit, - ffit, - fffit, beforeEach, afterEach } = require('./async-spec-helpers') diff --git a/spec/command-registry-spec.js b/spec/command-registry-spec.js index 285cec055..f49ebe942 100644 --- a/spec/command-registry-spec.js +++ b/spec/command-registry-spec.js @@ -1,13 +1,6 @@ const CommandRegistry = require('../src/command-registry') const _ = require('underscore-plus') -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') describe('CommandRegistry', () => { let registry, parent, child, grandchild diff --git a/spec/config-file-spec.js b/spec/config-file-spec.js index a053c9755..1350853f5 100644 --- a/spec/config-file-spec.js +++ b/spec/config-file-spec.js @@ -1,10 +1,8 @@ const { it, - fit, - ffit, + beforeEach, - afterEach, - conditionPromise + afterEach } = require('./async-spec-helpers') const fs = require('fs-plus') const path = require('path') diff --git a/spec/dock-spec.js b/spec/dock-spec.js index 6b97b6aa8..d7bd5b1cb 100644 --- a/spec/dock-spec.js +++ b/spec/dock-spec.js @@ -2,14 +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 @@ -344,7 +337,7 @@ describe('Dock', () => { }, serialize: () => ({ deserializer: 'DockTestItem' }) } - const itemDeserializer = atom.deserializers.add({ + atom.deserializers.add({ name: 'DockTestItem', deserialize: () => item }) diff --git a/spec/git-repository-provider-spec.js b/spec/git-repository-provider-spec.js index d70d7db3f..28e2f5eb8 100644 --- a/spec/git-repository-provider-spec.js +++ b/spec/git-repository-provider-spec.js @@ -4,7 +4,7 @@ const temp = require('temp').track() 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 diff --git a/spec/git-repository-spec.js b/spec/git-repository-spec.js index 60a0846ac..ade09da88 100644 --- a/spec/git-repository-spec.js +++ b/spec/git-repository-spec.js @@ -1,11 +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() @@ -424,8 +417,6 @@ describe('GitRepository', () => { await project2.deserialize(atom.project.serialize({ isUnloading: false })) buffer = project2.getBuffers()[0] - - const originalContent = buffer.getText() buffer.append('changes') statusHandler = jasmine.createSpy('statusHandler') diff --git a/spec/grammar-registry-spec.js b/spec/grammar-registry-spec.js index 2f7d82299..729d52563 100644 --- a/spec/grammar-registry-spec.js +++ b/spec/grammar-registry-spec.js @@ -1,11 +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') @@ -307,7 +300,7 @@ describe('GrammarRegistry', () => { 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) diff --git a/spec/history-manager-spec.js b/spec/history-manager-spec.js index 2d1a09cdc..5f7366118 100644 --- a/spec/history-manager-spec.js +++ b/spec/history-manager-spec.js @@ -1,12 +1,4 @@ -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 StateStore = require('../src/state-store') diff --git a/spec/package-manager-spec.js b/spec/package-manager-spec.js index 9dec5bde6..6e67508b4 100644 --- a/spec/package-manager-spec.js +++ b/spec/package-manager-spec.js @@ -8,7 +8,7 @@ const { Disposable } = require('atom') const { buildKeydownEvent } = require('../src/keymap-extensions') const { mockLocalStorage } = require('./spec-helper') const ModuleCache = require('../src/module-cache') -const { it, fit, ffit, beforeEach, afterEach } = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') describe('PackageManager', () => { function createTestElement (className) { diff --git a/spec/package-transpilation-registry-spec.js b/spec/package-transpilation-registry-spec.js index 90a06ea6c..32b3f375b 100644 --- a/spec/package-transpilation-registry-spec.js +++ b/spec/package-transpilation-registry-spec.js @@ -1,15 +1,7 @@ /** @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' diff --git a/spec/pane-container-spec.js b/spec/pane-container-spec.js index 50a60d2b0..7450d870b 100644 --- a/spec/pane-container-spec.js +++ b/spec/pane-container-spec.js @@ -1,11 +1,8 @@ const PaneContainer = require('../src/pane-container') const { it, - fit, - ffit, - fffit, - beforeEach, - afterEach + + beforeEach } = require('./async-spec-helpers') describe('PaneContainer', () => { diff --git a/spec/pane-spec.js b/spec/pane-spec.js index b87e9e8ad..17fffaec7 100644 --- a/spec/pane-spec.js +++ b/spec/pane-spec.js @@ -5,9 +5,6 @@ const Pane = require('../src/pane') const PaneContainer = require('../src/pane-container') const { it, - fit, - ffit, - fffit, beforeEach, conditionPromise, timeoutPromise diff --git a/spec/panel-spec.js b/spec/panel-spec.js index 7e1365a67..5165e550c 100644 --- a/spec/panel-spec.js +++ b/spec/panel-spec.js @@ -108,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') }) }) }) diff --git a/spec/reopen-project-menu-manager-spec.js b/spec/reopen-project-menu-manager-spec.js index 100111242..f5745bc76 100644 --- a/spec/reopen-project-menu-manager-spec.js +++ b/spec/reopen-project-menu-manager-spec.js @@ -1,14 +1,7 @@ /** @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') diff --git a/spec/state-store-spec.js b/spec/state-store-spec.js index 95583f8cd..d890877ab 100644 --- a/spec/state-store-spec.js +++ b/spec/state-store-spec.js @@ -1,12 +1,5 @@ /** @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') diff --git a/spec/style-manager-spec.js b/spec/style-manager-spec.js index e29dedb0c..95ec0dacf 100644 --- a/spec/style-manager-spec.js +++ b/spec/style-manager-spec.js @@ -152,7 +152,7 @@ describe('StyleManager', () => { 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}', { + styleManager.addStyleSheet('a {color: red}', { sourcePath: '/foo/bar' }) expect(addEvents.length).toBe(1) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index d58a749d6..42e243830 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -1,12 +1,9 @@ const { it, - fit, - ffit, - fffit, + beforeEach, afterEach, - conditionPromise, - timeoutPromise + conditionPromise } = require('./async-spec-helpers') const Random = require('../script/node_modules/random-seed') @@ -194,7 +191,7 @@ describe('TextEditorComponent', () => { }) it('re-renders lines when their height changes', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ rowsPerTile: 3, autoHeight: false }) @@ -235,7 +232,7 @@ describe('TextEditorComponent', () => { }) it('makes the content at least as tall as the scroll container client height', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ text: 'a'.repeat(100), width: 50, height: 100 @@ -253,11 +250,10 @@ describe('TextEditorComponent', () => { }) it('honors the scrollPastEnd option by adding empty space equivalent to the clientHeight to the end of the content area', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ autoHeight: false, autoWidth: false }) - const { scrollContainer } = component.refs await editor.update({ scrollPastEnd: true }) await setEditorHeightInLines(component, 6) @@ -307,7 +303,7 @@ describe('TextEditorComponent', () => { }) it('gives the line number tiles an explicit width and height so their layout can be strictly contained', async () => { - const { component, element, editor } = buildComponent({ rowsPerTile: 3 }) + const { component, editor } = buildComponent({ rowsPerTile: 3 }) const lineNumberGutterElement = component.refs.gutterContainer.refs.lineNumberGutter.element @@ -344,7 +340,7 @@ describe('TextEditorComponent', () => { }) it('keeps the number of tiles stable when the visible line count changes during vertical scrolling', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ rowsPerTile: 3, autoHeight: false }) @@ -359,7 +355,7 @@ describe('TextEditorComponent', () => { }) it('recycles tiles on resize', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ rowsPerTile: 2, autoHeight: false }) @@ -371,7 +367,7 @@ describe('TextEditorComponent', () => { }) it("updates lines numbers when a row's foldability changes (regression)", async () => { - const { component, element, editor } = buildComponent({ text: 'abc\n' }) + const { component, editor } = buildComponent({ text: 'abc\n' }) editor.setCursorBufferPosition([1, 0]) await component.getNextUpdatePromise() expect( @@ -392,7 +388,7 @@ describe('TextEditorComponent', () => { }) it('shows the foldable icon on the last screen row of a buffer row that can be folded', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ text: 'abc\n de\nfghijklm\n no', softWrapped: true }) @@ -415,7 +411,7 @@ describe('TextEditorComponent', () => { }) it('renders dummy vertical and horizontal scrollbars when content overflows', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ height: 100, width: 100 }) @@ -708,7 +704,7 @@ describe('TextEditorComponent', () => { }) it('places the hidden input element at the location of the last cursor if it is visible', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ height: 60, width: 120, rowsPerTile: 2 @@ -789,7 +785,7 @@ describe('TextEditorComponent', () => { }) it('decorates the line numbers of folded lines', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() editor.foldBufferRow(1) await component.getNextUpdatePromise() expect( @@ -799,7 +795,7 @@ describe('TextEditorComponent', () => { it('makes lines at least as wide as the scrollContainer', async () => { const { component, element, editor } = buildComponent() - const { scrollContainer, gutterContainer } = component.refs + const { scrollContainer } = component.refs editor.setText('a') await component.getNextUpdatePromise() @@ -815,7 +811,6 @@ describe('TextEditorComponent', () => { }) const editorPadding = 3 element.style.padding = editorPadding + 'px' - const { gutterContainer, scrollContainer } = component.refs const initialWidth = element.offsetWidth const initialHeight = element.offsetHeight expect(initialWidth).toBe( @@ -854,7 +849,7 @@ describe('TextEditorComponent', () => { }) it('does not render the line number gutter at all if the isLineNumberGutterVisible parameter is false', () => { - const { component, element, editor } = buildComponent({ + const { element } = buildComponent({ lineNumberGutterVisible: false }) expect(element.querySelector('.line-number')).toBe(null) @@ -1063,7 +1058,7 @@ describe('TextEditorComponent', () => { it('does not blow away class names added to the element by packages when changing the class name', async () => { assertDocumentFocused() - const { component, element, editor } = buildComponent() + const { component, element } = buildComponent() element.classList.add('a', 'b') expect(element.className).toBe('editor a b') element.focus() @@ -1076,7 +1071,7 @@ describe('TextEditorComponent', () => { it('does not blow away class names managed by the component when packages change the element class name', async () => { assertDocumentFocused() - const { component, element, editor } = buildComponent({ mini: true }) + const { component, element } = buildComponent({ mini: true }) element.classList.add('a', 'b') element.focus() await component.getNextUpdatePromise() @@ -1087,7 +1082,7 @@ describe('TextEditorComponent', () => { }) it('ignores resize events when the editor is hidden', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ autoHeight: false }) element.style.height = 5 * component.getLineHeight() + 'px' @@ -1258,13 +1253,13 @@ describe('TextEditorComponent', () => { describe('mini editors', () => { it('adds the mini attribute and class even when the element is not attached', () => { { - const { element, editor } = buildComponent({ mini: true }) + const { element } = buildComponent({ mini: true }) expect(element.hasAttribute('mini')).toBe(true) expect(element.classList.contains('mini')).toBe(true) } { - const { element, editor } = buildComponent({ + const { element } = buildComponent({ mini: true, attach: false }) @@ -1274,7 +1269,7 @@ describe('TextEditorComponent', () => { }) it('does not render the gutter container', () => { - const { component, element, editor } = buildComponent({ mini: true }) + const { component, element } = buildComponent({ mini: true }) expect(component.refs.gutterContainer).toBeUndefined() expect(element.querySelector('gutter-container')).toBeNull() }) @@ -1299,7 +1294,7 @@ describe('TextEditorComponent', () => { }) it('does not render scrollbars', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ mini: true, autoHeight: false }) @@ -1321,7 +1316,7 @@ describe('TextEditorComponent', () => { }) it('focuses the hidden input element and adds the is-focused class when focused', async () => { - const { component, element, editor } = buildComponent() + const { component, element } = buildComponent() const { hiddenInput } = component.refs.cursorsAndInput.refs expect(document.activeElement).not.toBe(hiddenInput) @@ -1341,7 +1336,7 @@ describe('TextEditorComponent', () => { }) it('updates the component when the hidden input is focused directly', async () => { - const { component, element, editor } = buildComponent() + const { component, element } = buildComponent() const { hiddenInput } = component.refs.cursorsAndInput.refs expect(element.classList.contains('is-focused')).toBe(false) expect(document.activeElement).not.toBe(hiddenInput) @@ -1352,7 +1347,7 @@ describe('TextEditorComponent', () => { }) it('gracefully handles a focus event that occurs prior to the attachedCallback of the element', () => { - const { component, element, editor } = buildComponent({ attach: false }) + const { component, element } = buildComponent({ attach: false }) const parent = document.createElement( 'text-editor-component-test-element' ) @@ -1365,7 +1360,7 @@ describe('TextEditorComponent', () => { }) it('gracefully handles a focus event that occurs prior to detecting the element has become visible', async () => { - const { component, element, editor } = buildComponent({ attach: false }) + const { component, element } = buildComponent({ attach: false }) element.style.display = 'none' jasmine.attachToDOM(element) element.style.display = 'block' @@ -1475,7 +1470,6 @@ describe('TextEditorComponent', () => { it('automatically scrolls horizontally when the requested range is within the horizontal scroll margin of the right edge of the gutter or right edge of the scroll container', async () => { const { component, element, editor } = buildComponent() - const { scrollContainer } = component.refs element.style.width = component.getGutterContainerWidth() + 3 * @@ -1560,7 +1554,6 @@ describe('TextEditorComponent', () => { const { component, element, editor } = buildComponent({ autoHeight: false }) - const { scrollContainer } = component.refs element.style.height = component.getContentHeight() / 2 + 'px' element.style.width = component.getScrollWidth() + 'px' await component.getNextUpdatePromise() @@ -1587,7 +1580,7 @@ describe('TextEditorComponent', () => { describe('logical scroll positions', () => { it('allows the scrollTop to be changed and queried in terms of rows via setScrollTopRow and getScrollTopRow', () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ attach: false, height: 80 }) @@ -1682,7 +1675,7 @@ describe('TextEditorComponent', () => { describe('scrolling via the mouse wheel', () => { it('scrolls vertically or horizontally depending on whether deltaX or deltaY is larger', () => { const scrollSensitivity = 30 - const { component, editor } = buildComponent({ + const { component } = buildComponent({ height: 50, width: 50, scrollSensitivity @@ -1737,7 +1730,7 @@ describe('TextEditorComponent', () => { it('inverts deltaX and deltaY when holding shift on Windows and Linux', async () => { const scrollSensitivity = 50 - const { component, editor } = buildComponent({ + const { component } = buildComponent({ height: 50, width: 50, scrollSensitivity @@ -1864,7 +1857,7 @@ describe('TextEditorComponent', () => { describe('scrolling via the API', () => { it('ignores scroll requests to NaN, null or undefined positions', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ rowsPerTile: 2, autoHeight: false }) @@ -1901,7 +1894,7 @@ describe('TextEditorComponent', () => { describe('line and line number decorations', () => { it('adds decoration classes on screen lines spanned by decorated markers', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ softWrapped: true }) await setEditorWidthInCharacters(component, 55) @@ -1914,10 +1907,10 @@ describe('TextEditorComponent', () => { const marker1 = editor.markScreenRange([[1, 10], [3, 10]]) const layer = editor.addMarkerLayer() - const marker2 = layer.markScreenPosition([5, 0]) - const marker3 = layer.markScreenPosition([8, 0]) + layer.markScreenPosition([5, 0]) + layer.markScreenPosition([8, 0]) const marker4 = layer.markScreenPosition([10, 0]) - const markerDecoration = editor.decorateMarker(marker1, { + editor.decorateMarker(marker1, { type: ['line', 'line-number'], class: 'a' }) @@ -2048,7 +2041,7 @@ describe('TextEditorComponent', () => { }) it('honors the onlyEmpty and onlyNonEmpty decoration options', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markScreenPosition([1, 0]) editor.decorateMarker(marker, { type: ['line', 'line-number'], @@ -2121,7 +2114,7 @@ describe('TextEditorComponent', () => { }) it('honors the onlyHead option', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markScreenRange([[1, 4], [3, 4]]) editor.decorateMarker(marker, { type: ['line', 'line-number'], @@ -2145,7 +2138,7 @@ describe('TextEditorComponent', () => { }) it('only decorates the last row of non-empty ranges that end at column 0 if omitEmptyLastRow is false', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markScreenRange([[1, 0], [3, 0]]) editor.decorateMarker(marker, { type: ['line', 'line-number'], @@ -2180,7 +2173,7 @@ describe('TextEditorComponent', () => { }) it('does not decorate invalidated markers', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markScreenRange([[1, 0], [3, 0]], { invalidate: 'touch' }) @@ -2533,7 +2526,7 @@ describe('TextEditorComponent', () => { } it('renders overlay elements at the specified screen position unless it would overflow the window', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ width: 200, height: 100, attach: false @@ -2634,7 +2627,7 @@ describe('TextEditorComponent', () => { }) it('does not attempt to avoid overflowing the window if `avoidOverflow` is false on the decoration', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ width: 200, height: 100, attach: false @@ -2646,7 +2639,7 @@ describe('TextEditorComponent', () => { overlayElement.style.margin = '3px' overlayElement.style.backgroundColor = 'red' const marker = editor.markScreenPosition([4, 25]) - const decoration = editor.decorateMarker(marker, { + editor.decorateMarker(marker, { type: 'overlay', item: overlayElement, avoidOverflow: false @@ -2666,7 +2659,7 @@ describe('TextEditorComponent', () => { describe('custom gutter decorations', () => { it('arranges custom gutters based on their priority', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() editor.addGutter({ name: 'e', priority: 2 }) editor.addGutter({ name: 'a', priority: -2 }) editor.addGutter({ name: 'd', priority: 1 }) @@ -2683,7 +2676,7 @@ describe('TextEditorComponent', () => { }) it('adjusts the left edge of the scroll container based on changes to the gutter container width', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const { scrollContainer, gutterContainer } = component.refs function checkScrollContainerLeft () { @@ -2740,7 +2733,7 @@ describe('TextEditorComponent', () => { }) it('can show and hide custom gutters', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const gutterA = editor.addGutter({ name: 'a', priority: -1 }) const gutterB = editor.addGutter({ name: 'b', priority: 1 }) const gutterAElement = gutterA.getElement() @@ -2978,25 +2971,16 @@ describe('TextEditorComponent', () => { height: 33, position: 'before' }) - const { - item: item4, - decoration: decoration4 - } = createBlockDecorationAtScreenRow(editor, 7, { + const { item: item4 } = createBlockDecorationAtScreenRow(editor, 7, { height: 44, position: 'before' }) - const { - item: item5, - decoration: decoration5 - } = createBlockDecorationAtScreenRow(editor, 7, { + const { item: item5 } = createBlockDecorationAtScreenRow(editor, 7, { height: 50, marginBottom: 5, position: 'after' }) - const { - item: item6, - decoration: decoration6 - } = createBlockDecorationAtScreenRow(editor, 12, { + const { item: item6 } = createBlockDecorationAtScreenRow(editor, 12, { height: 60, marginTop: 6, position: 'after' @@ -3343,7 +3327,7 @@ describe('TextEditorComponent', () => { }) it('correctly positions line numbers when block decorations are located at tile boundaries', async () => { - const { editor, component, element } = buildComponent({ rowsPerTile: 3 }) + const { editor, component } = buildComponent({ rowsPerTile: 3 }) createBlockDecorationAtScreenRow(editor, 0, { height: 5, position: 'before' @@ -3378,7 +3362,7 @@ describe('TextEditorComponent', () => { }) it('removes block decorations whose markers have been destroyed', async () => { - const { editor, component, element } = buildComponent({ rowsPerTile: 3 }) + const { editor, component } = buildComponent({ rowsPerTile: 3 }) const { marker } = createBlockDecorationAtScreenRow(editor, 2, { height: 5, position: 'before' @@ -3408,7 +3392,7 @@ describe('TextEditorComponent', () => { 3, { height: 44, position: 'before', invalidate: 'touch' } ) - const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) + const { component } = buildComponent({ editor, rowsPerTile: 3 }) // Invalidating the marker removes the block decoration. editor.getBuffer().deleteRows(2, 3) @@ -3460,7 +3444,7 @@ describe('TextEditorComponent', () => { it('does not render block decorations when decorating invalid markers', async () => { const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) - const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) + const { component } = buildComponent({ editor, rowsPerTile: 3 }) const marker = editor.markScreenPosition([3, 0], { invalidate: 'touch' }) const item = document.createElement('div') @@ -3468,7 +3452,7 @@ describe('TextEditorComponent', () => { item.style.width = 30 + 'px' editor.getBuffer().deleteRows(1, 4) - const decoration = editor.decorateMarker(marker, { + editor.decorateMarker(marker, { type: 'block', item, position: 'before' @@ -3498,12 +3482,11 @@ describe('TextEditorComponent', () => { it('does not try to remeasure block decorations whose markers are invalid (regression)', async () => { const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) - const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) - const { decoration, marker } = createBlockDecorationAtScreenRow( - editor, - 2, - { height: '12px', invalidate: 'touch' } - ) + const { component } = buildComponent({ editor, rowsPerTile: 3 }) + createBlockDecorationAtScreenRow(editor, 2, { + height: '12px', + invalidate: 'touch' + }) editor.getBuffer().deleteRows(0, 3) await component.getNextUpdatePromise() @@ -3579,7 +3562,7 @@ describe('TextEditorComponent', () => { const marker = editor.markScreenPosition([0, 0]) const item = document.createElement('div') item.textContent = 'block decoration' - const decoration = editor.decorateMarker(marker, { + editor.decorateMarker(marker, { type: 'block', item }) @@ -3596,7 +3579,7 @@ describe('TextEditorComponent', () => { const marker = editor.markScreenPosition([0, 0]) const item = document.createElement('div') item.textContent = 'block decoration that could wrap many times' - const decoration = editor.decorateMarker(marker, { + editor.decorateMarker(marker, { type: 'block', item }) @@ -3685,7 +3668,7 @@ describe('TextEditorComponent', () => { return lists }, [[], []]) - const [afterItems, afterDecorations] = [undefined, 1, 6, undefined, 6, 2] + const [afterItems] = [undefined, 1, 6, undefined, 6, 2] .map(order => { return createBlockDecorationAtScreenRow(editor, 2, { height: 10, @@ -3986,7 +3969,7 @@ describe('TextEditorComponent', () => { }) it('does not create empty text nodes when a text decoration ends right after a text tag', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markBufferRange([[0, 8], [0, 29]]) editor.decorateMarker(marker, { type: 'text', class: 'a' }) await component.getNextUpdatePromise() @@ -4009,7 +3992,7 @@ describe('TextEditorComponent', () => { describe('when there is only one cursor', () => { it('positions the cursor on single-click or when middle-clicking', async () => { for (const button of [0, 1]) { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const { lineHeight } = component.measurements editor.setCursorScreenPosition([Infinity, Infinity], { @@ -4319,7 +4302,7 @@ describe('TextEditorComponent', () => { }) it('expands the last selection on shift-click', () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() editor.setCursorScreenPosition([2, 18], { autoscroll: false }) component.didMouseDownOnContent( @@ -4493,8 +4476,7 @@ describe('TextEditorComponent', () => { ) const { - didDrag, - didStopDragging + didDrag } = component.handleMouseDragUntilMouseUp.argsForCall[1][0] didDrag(clientPositionForCharacter(component, 0, 8)) expect(editor.getSelectedScreenRange()).toEqual([[0, 4], [1, 5]]) @@ -4522,8 +4504,7 @@ describe('TextEditorComponent', () => { ) const { - didDrag, - didStopDragging + didDrag } = component.handleMouseDragUntilMouseUp.argsForCall[2][0] didDrag(clientPositionForCharacter(component, 1, 8)) expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]]) @@ -4554,7 +4535,7 @@ describe('TextEditorComponent', () => { }) it('autoscrolls the content when dragging near the edge of the scroll container', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ width: 200, height: 200 }) @@ -4585,8 +4566,7 @@ describe('TextEditorComponent', () => { clientY: 100 }) const { - didDrag, - didStopDragging + didDrag } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag({ clientX: 199, clientY: 199 }) @@ -4914,11 +4894,10 @@ describe('TextEditorComponent', () => { }) it('autoscrolls when dragging near the top or bottom of the gutter', async () => { - const { component, editor } = buildComponent({ + const { component } = buildComponent({ width: 200, height: 200 }) - const { scrollContainer } = component.refs spyOn(component, 'handleMouseDragUntilMouseUp') let previousScrollTop = 0 @@ -4944,8 +4923,7 @@ describe('TextEditorComponent', () => { clientY: 100 }) const { - didDrag, - didStopDragging + didDrag } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag({ clientX: 199, clientY: 199 }) assertScrolledDown() @@ -4995,7 +4973,7 @@ describe('TextEditorComponent', () => { describe('on the scrollbars', () => { it('delegates the mousedown events to the parent component unless the mousedown was on the actual scrollbar', async () => { - const { component, element, editor } = buildComponent({ height: 100 }) + const { component, editor } = buildComponent({ height: 100 }) await setEditorWidthInCharacters(component, 6) const verticalScrollbar = component.refs.verticalScrollbar @@ -5055,7 +5033,7 @@ describe('TextEditorComponent', () => { describe('keyboard input', () => { it('handles inserted accented characters via the press-and-hold menu on macOS correctly', () => { - const { editor, component, element } = buildComponent({ + const { editor, component } = buildComponent({ text: '', chromeVersion: 57 }) @@ -5417,7 +5395,7 @@ describe('TextEditorComponent', () => { }) it('maintains the scrollTopRow and scrollLeftColumn when the font size changes', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ rowsPerTile: 1, autoHeight: false }) @@ -5440,7 +5418,7 @@ describe('TextEditorComponent', () => { }) it('gracefully handles the editor being hidden after a styling change', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ autoHeight: false }) element.style.fontSize = @@ -5527,7 +5505,7 @@ describe('TextEditorComponent', () => { }) it('does not throw an exception on attachment when setting the soft-wrap column', () => { - const { component, element, editor } = buildComponent({ + const { element, editor } = buildComponent({ width: 435, attach: false, updatedSynchronously: true @@ -5565,7 +5543,7 @@ describe('TextEditorComponent', () => { describe('pixelPositionForScreenPosition(point)', () => { it('returns the pixel position for the given point, regardless of whether or not it is currently on screen', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ rowsPerTile: 2, autoHeight: false }) @@ -5636,7 +5614,7 @@ describe('TextEditorComponent', () => { }) it('does not get the component into an inconsistent state when the model has unflushed changes (regression)', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ rowsPerTile: 2, autoHeight: false, text: '' @@ -5649,12 +5627,12 @@ describe('TextEditorComponent', () => { }) it('does not shift cursors downward or render off-screen content when measuring off-screen lines (regression)', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ rowsPerTile: 2, autoHeight: false }) await setEditorHeightInLines(component, 3) - const { top, left } = component.pixelPositionForScreenPosition({ + component.pixelPositionForScreenPosition({ row: 12, column: 1 }) @@ -5679,7 +5657,7 @@ describe('TextEditorComponent', () => { describe('screenPositionForPixelPosition', () => { it('returns the screen position for the given pixel position, regardless of whether or not it is currently on screen', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ rowsPerTile: 2, autoHeight: false }) @@ -5749,7 +5727,7 @@ describe('TextEditorComponent', () => { describe('model methods that delegate to the component / element', () => { it('delegates setHeight and getHeight to the component', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ autoHeight: false }) spyOn(Grim, 'deprecate') @@ -5763,7 +5741,7 @@ describe('TextEditorComponent', () => { }) it('delegates setWidth and getWidth to the component', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() spyOn(Grim, 'deprecate') expect(editor.getWidth()).toBe(component.getScrollContainerWidth()) expect(Grim.deprecate.callCount).toBe(1) @@ -6138,10 +6116,6 @@ function getElementHeight (element) { return height } -function getNextTickPromise () { - return new Promise(resolve => process.nextTick(resolve)) -} - function queryOnScreenLineNumberElements (element) { return Array.from(element.querySelectorAll('.line-number:not(.dummy)')) } diff --git a/spec/text-editor-element-spec.js b/spec/text-editor-element-spec.js index b22d2c782..941dba78e 100644 --- a/spec/text-editor-element-spec.js +++ b/spec/text-editor-element-spec.js @@ -1,12 +1,7 @@ const { it, - fit, - ffit, - fffit, - beforeEach, - afterEach, - conditionPromise, - timeoutPromise + + beforeEach } = require('./async-spec-helpers') const TextEditor = require('../src/text-editor') const TextEditorElement = require('../src/text-editor-element') diff --git a/spec/text-editor-registry-spec.js b/spec/text-editor-registry-spec.js index c6303e4fd..715762855 100644 --- a/spec/text-editor-registry-spec.js +++ b/spec/text-editor-registry-spec.js @@ -2,7 +2,7 @@ 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 { it } = require('./async-spec-helpers') const dedent = require('dedent') describe('TextEditorRegistry', function () { @@ -287,7 +287,6 @@ describe('TextEditorRegistry', function () { atom.grammars.assignLanguageMode(editor, 'source.js') atom.config.set('editor.tabType', 'auto') await initialPackageActivation - const languageMode = editor.getBuffer().getLanguageMode() editor.setText(dedent` { diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 60c8076df..569c3e4cd 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -1,12 +1,8 @@ const { it, - fit, - ffit, - fffit, + beforeEach, - afterEach, - conditionPromise, - timeoutPromise + afterEach } = require('./async-spec-helpers') const fs = require('fs') @@ -384,7 +380,7 @@ describe('TextEditor', () => { it('merges multiple cursors', () => { editor.setCursorScreenPosition([0, 0]) editor.addCursorAtScreenPosition([0, 1]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.setCursorScreenPosition([4, 7]) expect(editor.getCursors().length).toBe(1) expect(editor.getCursors()).toEqual([cursor1]) @@ -450,7 +446,7 @@ describe('TextEditor', () => { it('merges cursors when they overlap', () => { editor.addCursorAtScreenPosition([1, 0]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.moveUp() expect(editor.getCursors()).toEqual([cursor1]) @@ -551,7 +547,7 @@ describe('TextEditor', () => { it('merges cursors when they overlap', () => { editor.setCursorScreenPosition([12, 2]) editor.addCursorAtScreenPosition([11, 2]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.moveDown() expect(editor.getCursors()).toEqual([cursor1]) @@ -668,7 +664,7 @@ describe('TextEditor', () => { editor.setCursorScreenPosition([0, 0]) editor.addCursorAtScreenPosition([0, 1]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.moveLeft() expect(editor.getCursors()).toEqual([cursor1]) expect(cursor1.getBufferPosition()).toEqual([0, 0]) @@ -754,7 +750,7 @@ describe('TextEditor', () => { it('merges cursors when they overlap', () => { editor.setCursorScreenPosition([12, 2]) editor.addCursorAtScreenPosition([12, 1]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.moveRight() expect(editor.getCursors()).toEqual([cursor1]) @@ -1501,8 +1497,9 @@ describe('TextEditor', () => { describe('::getCursorScreenPositions()', () => { it('returns the cursor positions in the order they were added', () => { editor.foldBufferRow(4) - const cursor1 = editor.addCursorAtBufferPosition([8, 5]) - const cursor2 = editor.addCursorAtBufferPosition([3, 5]) + editor.addCursorAtBufferPosition([8, 5]) + editor.addCursorAtBufferPosition([3, 5]) + expect(editor.getCursorScreenPositions()).toEqual([ [0, 0], [5, 5], @@ -1643,7 +1640,7 @@ describe('TextEditor', () => { [[1, 10], [1, 20]], [[2, 15], [3, 25]] ]) - const [selection1, selection2, selection3] = editor.getSelections() + const [selection1] = editor.getSelections() editor.selectDown() expect(editor.getSelections()).toEqual([selection1]) @@ -1656,7 +1653,7 @@ describe('TextEditor', () => { [[[0, 9], [0, 13]], [[1, 10], [1, 20]]], { reversed: true } ) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() editor.selectUp() expect(editor.getSelections().length).toBe(1) @@ -1670,7 +1667,7 @@ describe('TextEditor', () => { [[[0, 9], [0, 13]], [[0, 13], [1, 20]]], { reversed: true } ) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() editor.selectLeft() expect(editor.getSelections()).toEqual([selection1]) @@ -1680,7 +1677,7 @@ describe('TextEditor', () => { it('merges selections when they intersect when moving right', () => { editor.setSelectedBufferRanges([[[0, 9], [0, 14]], [[0, 14], [1, 20]]]) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() editor.selectRight() expect(editor.getSelections()).toEqual([selection1]) @@ -2310,7 +2307,7 @@ describe('TextEditor', () => { selection = editor.getLastSelection() editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[4, 4], [5, 5]]]) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() expect(selection1).toBe(selection) expect(selection1.getBufferRange()).toEqual([[2, 2], [3, 3]]) }) @@ -2374,7 +2371,7 @@ describe('TextEditor', () => { selection = editor.getLastSelection() editor.setSelectedScreenRanges([[[2, 2], [3, 4]], [[4, 4], [5, 5]]]) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() expect(selection1).toBe(selection) expect(selection1.getScreenRange()).toEqual([[2, 2], [3, 4]]) }) @@ -4724,8 +4721,6 @@ describe('TextEditor', () => { it('deletes as normal', () => { editor.foldBufferRow(4) editor.setCursorScreenPosition([3, 4]) - const cursorPositionBefore = editor.getCursorScreenPosition() - editor.delete() expect(buffer.lineForRow(3)).toBe( @@ -5236,19 +5231,6 @@ describe('TextEditor', () => { }) describe('.pasteText()', () => { - const copyText = function (text, { startColumn, textEditor } = {}) { - if (startColumn == null) startColumn = 0 - if (textEditor == null) textEditor = editor - textEditor.setCursorBufferPosition([0, 0]) - textEditor.insertText(text) - const numberOfNewlines = text.match(/\n/g).length - const endColumn = text.match(/[^\n]*$/)[0].length - textEditor - .getLastSelection() - .setBufferRange([[0, startColumn], [numberOfNewlines, endColumn]]) - return textEditor.cutSelectedText() - } - it('pastes text into the buffer', () => { editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) atom.clipboard.write('first') @@ -5854,7 +5836,6 @@ describe('TextEditor', () => { editor.delete() editor.delete() - const selections = editor.getSelections() expect(buffer.lineForRow(1)).toBe(' var = function( {') expect(editor.getSelectedBufferRanges()).toEqual([ @@ -6108,7 +6089,7 @@ describe('TextEditor', () => { editor.addCursorAtScreenPosition([0, 2]) editor.addCursorAtScreenPosition([1, 2]) - const [cursor1, cursor2, cursor3] = editor.getCursors() + const [cursor1, , cursor3] = editor.getCursors() expect(editor.getCursors().length).toBe(3) buffer.delete([[0, 0], [0, 2]]) @@ -7874,11 +7855,8 @@ describe('TextEditor', () => { it("does not throw errors after the marker's containing layer is destroyed", () => { const layer = editor.addMarkerLayer() - const marker = layer.markBufferRange([[2, 4], [6, 8]]) - const decoration = editor.decorateMarker(marker, { - type: 'highlight', - class: 'foo' - }) + layer.markBufferRange([[2, 4], [6, 8]]) + layer.destroy() editor.decorationsStateForScreenRowRange(0, 5) }) diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index 3b1aae9b5..be713ec78 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -1,17 +1,10 @@ const NullGrammar = require('../src/null-grammar') const TextMateLanguageMode = require('../src/text-mate-language-mode') const TextBuffer = require('text-buffer') -const { Point, Range } = TextBuffer +const { Point } = TextBuffer const _ = require('underscore-plus') const dedent = require('dedent') -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') describe('TextMateLanguageMode', () => { let languageMode, buffer, config diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index e4b41b994..749544f17 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1,11 +1,4 @@ -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') const fs = require('fs') const path = require('path') diff --git a/spec/update-process-env-spec.js b/spec/update-process-env-spec.js index db702bd5b..54b6a9038 100644 --- a/spec/update-process-env-spec.js +++ b/spec/update-process-env-spec.js @@ -1,14 +1,7 @@ /** @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 { @@ -16,7 +9,6 @@ import { shouldGetEnvFromShell } from '../src/update-process-env' import dedent from 'dedent' -import { EventEmitter } from 'events' import mockSpawn from 'mock-spawn' const temp = require('temp').track() diff --git a/spec/workspace-center-spec.js b/spec/workspace-center-spec.js index 055b463db..681074557 100644 --- a/spec/workspace-center-spec.js +++ b/spec/workspace-center-spec.js @@ -2,14 +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()', () => { diff --git a/spec/workspace-element-spec.js b/spec/workspace-element-spec.js index b11e8b443..d3d6e0fd5 100644 --- a/spec/workspace-element-spec.js +++ b/spec/workspace-element-spec.js @@ -5,14 +5,7 @@ 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 { it, beforeEach, afterEach } = require('./async-spec-helpers') const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise @@ -62,7 +55,6 @@ describe('WorkspaceElement', () => { pane6, pane7, pane8, - pane9, leftDockPane, rightDockPane, bottomDockPane, @@ -104,7 +96,7 @@ describe('WorkspaceElement', () => { pane6 = pane5.splitRight() pane8 = pane7.splitRight() - pane9 = pane8.splitRight() + pane8.splitRight() const leftDock = workspace.getLeftDock() const rightDock = workspace.getRightDock() diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index 265ae2ba9..cba8db6cf 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -12,9 +12,6 @@ const fs = require('fs-plus') const AtomEnvironment = require('../src/atom-environment') const { it, - fit, - ffit, - fffit, beforeEach, afterEach, conditionPromise @@ -1844,9 +1841,6 @@ describe('Workspace', () => { workspace.observeActiveTextEditor(editor => observed.push(editor)) const editorAddedAfterRegisteringObserver = new TextEditor() - const nonEditorItemAddedAfterRegisteringObserver = document.createElement( - 'div' - ) pane.activateItem(editorAddedAfterRegisteringObserver) expect(observed).toEqual([ @@ -1904,7 +1898,7 @@ describe('Workspace', () => { const nonEditorItem1 = document.createElement('div') const nonEditorItem2 = document.createElement('div') pane.activateItem(nonEditorItem1) - pane.activateItem(nonEditorItem1) + pane.activateItem(nonEditorItem2) expect(observed).toEqual([]) }) From cd302135f0a19c6f3d03dd555d228556f523c741 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 11:44:30 +0100 Subject: [PATCH 3/8] Fix undefined variables from specs --- spec/atom-environment-spec.js | 10 +++++----- spec/atom-paths-spec.js | 1 + spec/main-process/file-recovery-service.test.js | 1 + spec/main-process/parse-command-line.test.js | 1 + spec/reopen-project-menu-manager-spec.js | 9 +++++---- spec/text-editor-element-spec.js | 2 +- spec/text-mate-language-mode-spec.js | 8 ++++++-- spec/workspace-element-spec.js | 3 ++- spec/workspace-spec.js | 4 ++-- 9 files changed, 24 insertions(+), 15 deletions(-) diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index a032b8eb2..9fb6a1999 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -71,9 +71,9 @@ describe('AtomEnvironment', () => { it('will open the dev tools when an error is triggered', async () => { try { - a + 1 // eslint-ignore-line no-unused-vars + 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 @@ -92,7 +92,7 @@ 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) @@ -113,7 +113,7 @@ 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) } @@ -132,7 +132,7 @@ describe('AtomEnvironment', () => { 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) diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index b7644e7cd..b7e489aef 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -73,6 +73,7 @@ describe('AtomPaths', () => { }) describe('setUserData', () => { + let tempAtomConfigPath = null let tempAtomHomePath = null let electronUserDataPath = null let defaultElectronUserDataPath = null diff --git a/spec/main-process/file-recovery-service.test.js b/spec/main-process/file-recovery-service.test.js index 25484f6c2..c47ffb944 100644 --- a/spec/main-process/file-recovery-service.test.js +++ b/spec/main-process/file-recovery-service.test.js @@ -3,6 +3,7 @@ const FileRecoveryService = require('../../src/main-process/file-recovery-servic 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 temp = require('temp').track() diff --git a/spec/main-process/parse-command-line.test.js b/spec/main-process/parse-command-line.test.js index 2fcece469..6b5ac3ba5 100644 --- a/spec/main-process/parse-command-line.test.js +++ b/spec/main-process/parse-command-line.test.js @@ -1,3 +1,4 @@ +const { assert } = require('chai') const parseCommandLine = require('../../src/main-process/parse-command-line') describe('parseCommandLine', () => { diff --git a/spec/reopen-project-menu-manager-spec.js b/spec/reopen-project-menu-manager-spec.js index f5745bc76..442c1a0e5 100644 --- a/spec/reopen-project-menu-manager-spec.js +++ b/spec/reopen-project-menu-manager-spec.js @@ -5,7 +5,7 @@ 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 @@ -15,6 +15,7 @@ numberRange = (low, high) => { describe('ReopenProjectMenuManager', () => { let menuManager, commandRegistry, config, historyManager, reopenProjects let commandDisposable, configDisposable, historyDisposable + let openFunction beforeEach(() => { menuManager = jasmine.createSpyObj('MenuManager', ['add']) @@ -92,7 +93,7 @@ describe('ReopenProjectMenuManager', () => { ]) reopenProjects.update() - reopenProjectCommand = + const reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project'] reopenProjectCommand({ detail: { index: 1 } }) @@ -101,7 +102,7 @@ describe('ReopenProjectMenuManager', () => { }) it('does not call open when no command detail is supplied', () => { - reopenProjectCommand = + const reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project'] reopenProjectCommand({}) @@ -109,7 +110,7 @@ describe('ReopenProjectMenuManager', () => { }) it('does not call open when no command detail index is supplied', () => { - reopenProjectCommand = + const reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project'] reopenProjectCommand({ detail: { anything: 'here' } }) diff --git a/spec/text-editor-element-spec.js b/spec/text-editor-element-spec.js index 941dba78e..758384f9e 100644 --- a/spec/text-editor-element-spec.js +++ b/spec/text-editor-element-spec.js @@ -370,7 +370,7 @@ describe('TextEditorElement', () => { describe('::setScrollTop and ::setScrollLeft', () => { it('changes the scroll position', async () => { - element = buildTextEditorElement() + const element = buildTextEditorElement() element.getModel().update({ autoHeight: false }) element.getModel().setText('lorem\nipsum\ndolor\nsit\namet') element.setHeight(20) diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index be713ec78..eedb4b63d 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -1038,6 +1038,8 @@ describe('TextMateLanguageMode', () => { }) describe('.isFoldableAtRow(row)', () => { + let editor + beforeEach(() => { buffer = atom.project.bufferForPathSync('sample.js') buffer.insert([10, 0], ' // multi-line\n // comment\n // block\n') @@ -1145,6 +1147,8 @@ describe('TextMateLanguageMode', () => { }) describe('.getFoldableRangesAtIndentLevel', () => { + let editor + it('returns the ranges that can be folded at the given indent level', () => { buffer = new TextBuffer(dedent` if (a) { @@ -1258,7 +1262,7 @@ describe('TextMateLanguageMode', () => { it('works with multi-line comments', async () => { await atom.packages.activatePackage('language-javascript') - editor = await atom.workspace.open('sample-with-comments.js', { + const editor = await atom.workspace.open('sample-with-comments.js', { autoIndent: false }) fullyTokenize(editor.getBuffer().getLanguageMode()) @@ -1409,7 +1413,7 @@ describe('TextMateLanguageMode', () => { it('searches upward and downward for surrounding comment lines and folds them as a single fold', async () => { await atom.packages.activatePackage('language-javascript') - editor = await atom.workspace.open('sample-with-comments.js') + const editor = await atom.workspace.open('sample-with-comments.js') editor.buffer.insert( [1, 0], ' //this is a comment\n // and\n //more docs\n\n//second comment' diff --git a/spec/workspace-element-spec.js b/spec/workspace-element-spec.js index d3d6e0fd5..930fedeae 100644 --- a/spec/workspace-element-spec.js +++ b/spec/workspace-element-spec.js @@ -47,7 +47,8 @@ describe('WorkspaceElement', () => { }) describe('finding the nearest visible pane in a specific direction', () => { - let pane1, + let nearestPaneElement, + pane1, pane2, pane3, pane4, diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index cba8db6cf..c5e3ff668 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -1548,7 +1548,7 @@ describe('Workspace', () => { .getActivePane() .addItem(document.createElement('div')) - emittedItems = [] + const emittedItems = [] atom.workspace.onDidStopChangingActivePaneItem(item => emittedItems.push(item) ) @@ -1831,7 +1831,7 @@ describe('Workspace', () => { describe('::observeActiveTextEditor()', () => { it('invokes the observer with current active text editor and each time a different text editor becomes active', () => { const pane = workspace.getCenter().getActivePane() - observed = [] + const observed = [] const inactiveEditorBeforeRegisteringObserver = new TextEditor() const activeEditorBeforeRegisteringObserver = new TextEditor() From 6c46cf924355d0735123c6c932552271930b69b8 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 12:19:35 +0100 Subject: [PATCH 4/8] Fix remaining linter issues --- spec/atom-environment-spec.js | 14 ++++++------ spec/atom-paths-spec.js | 3 ++- spec/text-editor-component-spec.js | 30 +++++++++++++------------- spec/text-editor-registry-spec.js | 4 ++++ spec/text-editor-spec.js | 2 +- spec/text-mate-language-mode-spec.js | 1 - spec/theme-manager-spec.js | 4 +--- spec/tree-sitter-language-mode-spec.js | 8 ++++--- 8 files changed, 35 insertions(+), 31 deletions(-) diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index 9fb6a1999..6b83035d9 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -95,7 +95,7 @@ describe('AtomEnvironment', () => { 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 @@ -115,7 +115,7 @@ describe('AtomEnvironment', () => { try { 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() @@ -135,7 +135,7 @@ describe('AtomEnvironment', () => { 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(), @@ -678,12 +678,12 @@ 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({ diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index b7e489aef..0b2a8cdf9 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -22,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(() => { diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 42e243830..a1cd8d67e 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -173,21 +173,19 @@ describe('TextEditorComponent', () => { expect(actualWidth).toBe(expectedWidth + 'px') } - { - // Make sure we do not throw an error if a synchronous update is - // triggered before measuring the longest line from a - // previously-scheduled update. - editor.getBuffer().insert(Point(12, Infinity), 'x'.repeat(100)) - expect(editor.getLongestScreenRow()).toBe(12) + // Make sure we do not throw an error if a synchronous update is + // triggered before measuring the longest line from a + // previously-scheduled update. + editor.getBuffer().insert(Point(12, Infinity), 'x'.repeat(100)) + expect(editor.getLongestScreenRow()).toBe(12) - TextEditorComponent.getScheduler().readDocument(() => { - // This will happen before the measurement phase of the update - // triggered above. - component.pixelPositionForScreenPosition(Point(11, Infinity)) - }) + TextEditorComponent.getScheduler().readDocument(() => { + // This will happen before the measurement phase of the update + // triggered above. + component.pixelPositionForScreenPosition(Point(11, Infinity)) + }) - await component.getNextUpdatePromise() - } + await component.getNextUpdatePromise() }) it('re-renders lines when their height changes', async () => { @@ -1186,10 +1184,12 @@ describe('TextEditorComponent', () => { } else if (k < 95) { editor.setSelectedBufferRange(range) } else { - if (random(2)) + if (random(2)) { component.setScrollTop(random(component.getScrollHeight())) - if (random(2)) + } + if (random(2)) { component.setScrollLeft(random(component.getScrollWidth())) + } } component.scheduleUpdate() diff --git a/spec/text-editor-registry-spec.js b/spec/text-editor-registry-spec.js index 715762855..82afa3b0f 100644 --- a/spec/text-editor-registry-spec.js +++ b/spec/text-editor-registry-spec.js @@ -296,11 +296,13 @@ 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) @@ -317,6 +319,7 @@ describe('TextEditorRegistry', function () { disposable = registry.maintainConfig(editor) expect(editor.getSoftTabs()).toBe(false) + /* eslint-disable no-tabs */ editor.setText(dedent` /* * Comment with a leading space. @@ -326,6 +329,7 @@ describe('TextEditorRegistry', function () { hello; } `) + /* eslint-enable no-tabs */ disposable.dispose() disposable = registry.maintainConfig(editor) expect(editor.getSoftTabs()).toBe(false) diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 569c3e4cd..f70ec4a1e 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -4272,7 +4272,7 @@ describe('TextEditor', () => { await atom.packages.activatePackage('language-go') editor.update({ autoIndent: true }) atom.grammars.assignLanguageMode(editor, 'source.go') - editor.setText('fmt.Printf("some%s",\n "thing")') + editor.setText('fmt.Printf("some%s",\n "thing")') // eslint-disable-line no-tabs editor.setCursorBufferPosition([1, 10]) editor.insertNewline() expect(editor.indentationForBufferRow(1)).toBe(1) diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index eedb4b63d..6f60d527a 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -59,7 +59,6 @@ describe('TextMateLanguageMode', () => { languageMode = new TextMateLanguageMode({ buffer, config, - config, grammar: atom.grammars.grammarForScopeName('source.js') }) languageMode.startTokenizing() diff --git a/spec/theme-manager-spec.js b/spec/theme-manager-spec.js index 2de214921..2e4f74b50 100644 --- a/spec/theme-manager-spec.js +++ b/spec/theme-manager-spec.js @@ -498,9 +498,7 @@ h2 { expect(note.getType()).toBe('error') expect(note.getMessage()).toContain('Error loading') expect( - atom.styles.styleElementsBySourcePath[ - atom.styles.getUserStyleSheetPath() - ] + atom.styles.styleElementsBySourcePath[atom.styles.getUserStyleSheetPath()] ).toBeUndefined() }) }) diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index 749544f17..09f134cb0 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1,3 +1,5 @@ +/* eslint-disable no-template-curly-in-string */ + const { it, beforeEach, afterEach } = require('./async-spec-helpers') const fs = require('fs') @@ -830,7 +832,7 @@ describe('TreeSitterLanguageMode', () => { buffer.getLanguageMode().syncOperationLimit = 0 const initialSeed = Date.now() - for (let i = 0, trial_count = 10; i < trial_count; i++) { + for (let i = 0, trialCount = 10; i < trialCount; i++) { let seed = initialSeed + i // seed = 1541201470759 const random = Random(seed) @@ -842,7 +844,7 @@ describe('TreeSitterLanguageMode', () => { editor.displayLayer.getScreenLines() // Make several random edits. - for (let j = 0, edit_count = 1 + random(4); j < edit_count; j++) { + for (let j = 0, editCount = 1 + random(4); j < editCount; j++) { const editRoll = random(10) const range = getRandomBufferRange(random, buffer) @@ -894,7 +896,7 @@ describe('TreeSitterLanguageMode', () => { if (jasmine.getEnv().currentSpec.results().failedCount > 0) { console.log(tokens1) console.log(tokens2) - debugger + debugger // eslint-disable-line no-debugger break } } From 8daaf3834eaa09e1b962d42984930e1bc8a357a8 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 12:19:52 +0100 Subject: [PATCH 5/8] Enable linter on spec/ folder --- script/lib/lint-java-script-paths.js | 45 +++++++++++++++++++--------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/script/lib/lint-java-script-paths.js b/script/lib/lint-java-script-paths.js index 64ff22610..35815f7ae 100644 --- a/script/lib/lint-java-script-paths.js +++ b/script/lib/lint-java-script-paths.js @@ -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.indexOf(myPath) === -1 + ) + + 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) + } }) }) } From ccfd761a06e2dc6ce44e0bffcbb08659a1de3f2c Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 16:47:32 +0100 Subject: [PATCH 6/8] Fix linting issue after rebase --- spec/git-repository-provider-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/git-repository-provider-spec.js b/spec/git-repository-provider-spec.js index 28e2f5eb8..b0ccec89c 100644 --- a/spec/git-repository-provider-spec.js +++ b/spec/git-repository-provider-spec.js @@ -158,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) }) }) From 55cdc398f6fdf680ed2b8738ba101e4064192b0b Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Tue, 26 Feb 2019 19:00:44 +0100 Subject: [PATCH 7/8] Use `includes` instead of `indexOf` Co-Authored-By: rafeca --- script/lib/lint-java-script-paths.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/lint-java-script-paths.js b/script/lib/lint-java-script-paths.js index 35815f7ae..f237820ff 100644 --- a/script/lib/lint-java-script-paths.js +++ b/script/lib/lint-java-script-paths.js @@ -25,7 +25,7 @@ module.exports = async function () { ]) const paths = includePaths.filter( - myPath => excludePaths.indexOf(myPath) === -1 + myPath => !excludePaths.includes(myPath) ) return new Promise((resolve, reject) => { From 2dd2c299b3b08ab7abeeb5482d9f664efb5517eb Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Wed, 27 Feb 2019 11:32:07 +0100 Subject: [PATCH 8/8] Keep unneeded block in TextEditor spec as it's a common pattern --- spec/text-editor-component-spec.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index a1cd8d67e..4cef9f136 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -173,19 +173,22 @@ describe('TextEditorComponent', () => { expect(actualWidth).toBe(expectedWidth + 'px') } - // Make sure we do not throw an error if a synchronous update is - // triggered before measuring the longest line from a - // previously-scheduled update. - editor.getBuffer().insert(Point(12, Infinity), 'x'.repeat(100)) - expect(editor.getLongestScreenRow()).toBe(12) + // eslint-disable-next-line no-lone-blocks + { + // Make sure we do not throw an error if a synchronous update is + // triggered before measuring the longest line from a + // previously-scheduled update. + editor.getBuffer().insert(Point(12, Infinity), 'x'.repeat(100)) + expect(editor.getLongestScreenRow()).toBe(12) - TextEditorComponent.getScheduler().readDocument(() => { - // This will happen before the measurement phase of the update - // triggered above. - component.pixelPositionForScreenPosition(Point(11, Infinity)) - }) + TextEditorComponent.getScheduler().readDocument(() => { + // This will happen before the measurement phase of the update + // triggered above. + component.pixelPositionForScreenPosition(Point(11, Infinity)) + }) - await component.getNextUpdatePromise() + await component.getNextUpdatePromise() + } }) it('re-renders lines when their height changes', async () => {