From ea534dd126f5c0b5bef858bbf1f029bac808e4b9 Mon Sep 17 00:00:00 2001 From: Koza Date: Fri, 31 May 2024 09:49:15 +0200 Subject: [PATCH] Write a wrapper to eliminate done callbacks from async tests --- spec/atom-environment-spec.js | 124 ++---- spec/atom-paths-spec.js | 12 +- spec/buffered-node-process-spec.js | 8 +- spec/buffered-process-spec.js | 22 +- spec/command-registry-spec.js | 6 +- spec/config-file-spec.js | 16 +- spec/config-spec.js | 12 +- spec/decoration-manager-spec.js | 4 +- spec/default-directory-provider-spec.js | 10 +- spec/default-directory-searcher-spec.js | 4 +- spec/dock-spec.js | 36 +- spec/git-repository-provider-spec.js | 32 +- spec/git-repository-spec.js | 48 +- spec/grammar-registry-spec.js | 96 ++-- spec/helpers/jasmine2-singleton.js | 3 - spec/helpers/platform-filter.js | 4 +- spec/history-manager-spec.js | 39 +- spec/native-watcher-registry-spec.js | 27 +- spec/package-manager-spec.js | 227 +++------- spec/package-spec.js | 12 +- spec/pane-container-element-spec.js | 8 +- spec/pane-container-spec.js | 16 +- spec/pane-spec.js | 92 +--- spec/panel-container-element-spec.js | 4 +- spec/path-watcher-spec.js | 28 +- spec/project-spec.js | 110 ++--- spec/reopen-project-menu-manager-spec.js | 12 +- spec/runners/jasmine2-test-runner.js | 37 +- spec/scope-resolver-spec.js | 172 ++------ spec/state-store-spec.js | 4 +- spec/task-spec.js | 20 +- spec/text-editor-component-spec.js | 464 +++++--------------- spec/text-editor-element-spec.js | 36 +- spec/text-editor-registry-spec.js | 116 ++--- spec/text-editor-spec.js | 196 +++------ spec/text-mate-language-mode-spec.js | 72 +-- spec/theme-manager-spec.js | 52 +-- spec/tree-indenter-spec.js | 4 +- spec/tree-sitter-language-mode-spec.js | 32 +- spec/update-process-env-spec.js | 34 +- spec/uri-handler-registry-spec.js | 12 +- spec/view-registry-spec.js | 4 +- spec/wasm-tree-sitter-language-mode-spec.js | 356 ++++----------- spec/window-event-handler-spec.js | 6 +- spec/workspace-element-spec.js | 20 +- spec/workspace-spec.js | 459 +++++-------------- 46 files changed, 841 insertions(+), 2267 deletions(-) diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index 2f765be93e..9fb99c9aae 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -28,19 +28,15 @@ describe('AtomEnvironment', () => { let originalSize = null; beforeEach(() => (originalSize = atom.getSize())); - afterEach(async (done) => { + afterEach(async () => { await atom.setSize(originalSize.width, originalSize.height); - - done(); }); - it('sets the size of the window, and can retrieve the size just set', async (done) => { + 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 }); - - done(); }); }); }); @@ -81,7 +77,7 @@ describe('AtomEnvironment', () => { spyOn(atom, 'executeJavaScriptInDevTools'); }); - it('will open the dev tools when an error is triggered', async (done) => { + it('will open the dev tools when an error is triggered', async () => { try { a + 1; // eslint-disable-line no-undef, no-unused-expressions } catch (e) { @@ -91,8 +87,6 @@ describe('AtomEnvironment', () => { await devToolsPromise; expect(atom.openDevTools).toHaveBeenCalled(); expect(atom.executeJavaScriptInDevTools).toHaveBeenCalled(); - - done(); }); describe('::onWillThrowError', () => { @@ -219,7 +213,7 @@ describe('AtomEnvironment', () => { afterEach(() => (atom.enablePersistence = false)); - it('selects the state based on the current project paths', async (done) => { + it('selects the state based on the current project paths', async () => { jasmine.useRealClock(); const [dir1, dir2] = [temp.mkdirSync('dir1-'), temp.mkdirSync('dir2-')]; @@ -242,8 +236,6 @@ describe('AtomEnvironment', () => { loadSettings.initialProjectRoots = [dir2, dir1]; expect(await atom.loadState()).toEqual({ stuff: 'cool' }); - - done(); }); it('saves state when the CPU is idle after a keydown or mousedown event', () => { @@ -282,7 +274,7 @@ describe('AtomEnvironment', () => { atomEnv.destroy(); }); - it('ignores mousedown/keydown events happening after calling prepareToUnloadEditorWindow', async (done) => { + it('ignores mousedown/keydown events happening after calling prepareToUnloadEditorWindow', async () => { const atomEnv = new AtomEnvironment({ applicationDelegate: global.atom.applicationDelegate }); @@ -317,11 +309,9 @@ describe('AtomEnvironment', () => { expect(atomEnv.saveState.calls.count()).toBe(1); atomEnv.destroy(); - - done(); }); - it('serializes the project state with all the options supplied in saveState', async (done) => { + it('serializes the project state with all the options supplied in saveState', async () => { spyOn(atom.project, 'serialize').and.returnValue({ foo: 42 }); await atom.saveState({ anyOption: 'any option' }); @@ -329,11 +319,9 @@ describe('AtomEnvironment', () => { expect(atom.project.serialize.calls.mostRecent().args[0]).toEqual({ anyOption: 'any option' }); - - done(); }); - it('serializes the text editor registry', async (done) => { + it('serializes the text editor registry', async () => { await atom.packages.activatePackage('language-text'); const editor = await atom.workspace.open('sample.js'); expect(atom.grammars.assignLanguageMode(editor, 'text.plain')).toBe(true); @@ -358,12 +346,10 @@ describe('AtomEnvironment', () => { .getLanguageId() ).toBe('text.plain'); atom2.destroy(); - - done(); }); describe('deserialization failures', () => { - it('propagates unrecognized project state restoration failures', async (done) => { + it('propagates unrecognized project state restoration failures', async () => { let err; spyOn(atom.project, 'deserialize').and.callFake(() => { err = new Error('deserialization failure'); @@ -379,11 +365,9 @@ describe('AtomEnvironment', () => { stack: err.stack } ); - - done(); }); - it('disregards missing project folder errors', async (done) => { + it('disregards missing project folder errors', async () => { spyOn(atom.project, 'deserialize').and.callFake(() => { const err = new Error('deserialization failure'); err.missingProjectPaths = ['nah']; @@ -393,8 +377,6 @@ describe('AtomEnvironment', () => { await atom.deserialize({ project: 'should work' }); expect(atom.notifications.addError).not.toHaveBeenCalled(); - - done(); }); }); }); @@ -413,13 +395,11 @@ describe('AtomEnvironment', () => { }); }); - it('does not open an empty buffer when a buffer is already open', async (done) => { + it('does not open an empty buffer when a buffer is already open', async () => { await atom.workspace.open(); spyOn(atom.workspace, 'open'); atom.openInitialEmptyEditorIfNecessary(); expect(atom.workspace.open).not.toHaveBeenCalled(); - - done(); }); it('does not open an empty buffer when core.openEmptyEditorOnStart is false', () => { @@ -457,7 +437,7 @@ describe('AtomEnvironment', () => { spyOn(atom, 'attemptRestoreProjectStateForPaths'); }); - it('adds the selected folder to the project', async (done) => { + it('adds the selected folder to the project', async () => { atom.project.setPaths([]); const tempDirectory = temp.mkdirSync('a-new-directory'); spyOn(atom, 'pickFolder').and.callFake(callback => @@ -466,8 +446,6 @@ describe('AtomEnvironment', () => { await atom.addProjectFolder(); expect(atom.project.getPaths()).toEqual([tempDirectory]); expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalled(); - - done(); }); }); @@ -485,15 +463,13 @@ describe('AtomEnvironment', () => { }); describe('when there are no project folders', () => { - it('attempts to restore the project state', async (done) => { + it('attempts to restore the project state', async () => { await atom.addProjectFolder(); expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith( state, [__dirname] ); expect(atom.project.getPaths()).toEqual([]); - - done(); }); }); @@ -502,14 +478,12 @@ describe('AtomEnvironment', () => { beforeEach(() => atom.project.setPaths([openedPath])); - it('does not attempt to restore the project state, instead adding the project paths', async (done) => { + it('does not attempt to restore the project state, instead adding the project paths', async () => { await atom.addProjectFolder(); expect( atom.attemptRestoreProjectStateForPaths ).not.toHaveBeenCalled(); expect(atom.project.getPaths()).toEqual([openedPath, __dirname]); - - done(); }); }); }); @@ -517,14 +491,12 @@ describe('AtomEnvironment', () => { describe('attemptRestoreProjectStateForPaths(state, projectPaths, filesToOpen)', () => { describe('when the window is clean (empty or has only unnamed, unmodified buffers)', () => { - beforeEach(async (done) => { + beforeEach(async () => { // Unnamed, unmodified buffer doesn't count toward "clean"-ness await atom.workspace.open(); - - done(); }); - it('automatically restores the saved state into the current environment', async (done) => { + it('automatically restores the saved state into the current environment', async () => { const projectPath = temp.mkdirSync(); const filePath1 = path.join(projectPath, 'file-1'); const filePath2 = path.join(projectPath, 'file-2'); @@ -554,8 +526,6 @@ describe('AtomEnvironment', () => { const restoredURIs = env2.workspace.getPaneItems().map(p => p.getURI()); expect(restoredURIs).toEqual([filePath1, filePath2, filePath3]); env2.destroy(); - - done(); }); describe('when a dock has a non-text editor', () => { @@ -582,11 +552,9 @@ describe('AtomEnvironment', () => { describe('when the window is dirty', () => { let editor; - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open(); editor.setText('new editor'); - - done(); }); describe('when a dock has a modified editor', () => { @@ -606,7 +574,7 @@ describe('AtomEnvironment', () => { }); }); - it('prompts the user to restore the state in a new window, discarding it and adding folder to current window', async (done) => { + it('prompts the user to restore the state in a new window, discarding it and adding folder to current window', async () => { jasmine.useRealClock(); spyOn(atom, 'confirm').and.callFake((options, callback) => callback(1)); spyOn(atom.project, 'addPath'); @@ -624,11 +592,9 @@ describe('AtomEnvironment', () => { expect(atom.project.addPath).toHaveBeenCalledWith(__dirname); expect(atom.workspace.open.calls.count()).toBe(1); expect(atom.workspace.open).toHaveBeenCalledWith(__filename); - - done(); }); - it('prompts the user to restore the state in a new window, opening a new window', async (done) => { + it('prompts the user to restore the state in a new window, opening a new window', async () => { jasmine.useRealClock(); spyOn(atom, 'confirm').and.callFake((options, callback) => callback(0)); spyOn(atom, 'open'); @@ -647,8 +613,6 @@ describe('AtomEnvironment', () => { devMode: atom.inDevMode(), safeMode: atom.inSafeMode() }); - - done(); }); }); }); @@ -677,7 +641,7 @@ describe('AtomEnvironment', () => { }); describe('::destroy()', () => { - it('does not throw exceptions when unsubscribing from ipc events (regression)', async (done) => { + it('does not throw exceptions when unsubscribing from ipc events (regression)', async () => { const fakeDocument = { addEventListener() {}, removeEventListener() {}, @@ -696,8 +660,6 @@ describe('AtomEnvironment', () => { await atomEnvironment.startEditorWindow(); atomEnvironment.unloadEditorWindow(); atomEnvironment.destroy(); - - done(); }); }); @@ -725,22 +687,18 @@ describe('AtomEnvironment', () => { afterEach(() => atomEnvironment.destroy()); - it('is triggered once the shell environment is loaded', async (done) => { + it('is triggered once the shell environment is loaded', async () => { atomEnvironment.whenShellEnvironmentLoaded(spy); atomEnvironment.updateProcessEnvAndTriggerHooks(); await envLoaded(); expect(spy).toHaveBeenCalled(); - - done(); }); - it('triggers the callback immediately if the shell environment is already loaded', async (done) => { + it('triggers the callback immediately if the shell environment is already loaded', async () => { atomEnvironment.updateProcessEnvAndTriggerHooks(); await envLoaded(); atomEnvironment.whenShellEnvironmentLoaded(spy); expect(spy).toHaveBeenCalled(); - - done(); }); }); @@ -755,17 +713,15 @@ describe('AtomEnvironment', () => { }); describe('when the opened path exists', () => { - it('opens a file', async (done) => { + it('opens a file', async () => { const pathToOpen = __filename; await atom.openLocations([ { pathToOpen, exists: true, isFile: true } ]); expect(atom.project.getPaths()).toEqual([]); - - done(); }); - it('opens a directory as a project folder', async (done) => { + it('opens a directory as a project folder', async () => { const pathToOpen = __dirname; await atom.openLocations([ { pathToOpen, exists: true, isDirectory: true } @@ -774,13 +730,11 @@ describe('AtomEnvironment', () => { [] ); expect(atom.project.getPaths()).toEqual([pathToOpen]); - - done(); }); }); describe('when the opened path does not exist', () => { - it('opens it as a new file', async (done) => { + it('opens it as a new file', async () => { const pathToOpen = path.join( __dirname, 'this-path-does-not-exist.txt' @@ -790,11 +744,9 @@ describe('AtomEnvironment', () => { [pathToOpen] ); expect(atom.project.getPaths()).toEqual([]); - - done(); }); - it('may be required to be an existing directory', async (done) => { + it('may be required to be an existing directory', async () => { spyOn(atom.notifications, 'addWarning'); const nonExistent = path.join(__dirname, 'no'); @@ -816,8 +768,6 @@ describe('AtomEnvironment', () => { description: `The directories \`${nonExistent}\` and \`${existingFile}\` do not exist.` } ); - - done(); }); }); @@ -848,13 +798,11 @@ describe('AtomEnvironment', () => { serviceDisposable.dispose(); }); - it("adds it to the project's paths as is", async (done) => { + 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 }]); expect(atom.project.addPath).toHaveBeenCalledWith(pathToOpen); - - done(); }); }); }); @@ -875,7 +823,7 @@ describe('AtomEnvironment', () => { }); describe('when there are no project folders', () => { - it('attempts to restore the project state', async (done) => { + it('attempts to restore the project state', async () => { const pathToOpen = __dirname; await atom.openLocations([{ pathToOpen, isDirectory: true }]); expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith( @@ -884,11 +832,9 @@ describe('AtomEnvironment', () => { [] ); expect(atom.project.getPaths()).toEqual([]); - - done(); }); - it('includes missing mandatory project folders in computation of initial state key', async (done) => { + it('includes missing mandatory project folders in computation of initial state key', async () => { const existingDir = path.join(__dirname, 'fixtures'); const missingDir = path.join(__dirname, 'no'); @@ -911,11 +857,9 @@ describe('AtomEnvironment', () => { [] ); expect(atom.project.getPaths(), [existingDir]); - - done(); }); - it('opens the specified files', async (done) => { + it('opens the specified files', async () => { await atom.openLocations([ { pathToOpen: __dirname, isDirectory: true }, { pathToOpen: __filename } @@ -926,15 +870,13 @@ describe('AtomEnvironment', () => { [__filename] ); expect(atom.project.getPaths()).toEqual([]); - - done(); }); }); describe('when there are already project folders', () => { beforeEach(() => atom.project.setPaths([__dirname])); - it('does not attempt to restore the project state, instead adding the project paths', async (done) => { + 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, exists: true, isDirectory: true } @@ -943,11 +885,9 @@ describe('AtomEnvironment', () => { atom.attemptRestoreProjectStateForPaths ).not.toHaveBeenCalled(); expect(atom.project.getPaths()).toEqual([__dirname, pathToOpen]); - - done(); }); - it('opens the specified files', async (done) => { + it('opens the specified files', async () => { const pathToOpen = path.join(__dirname, 'fixtures'); const fileToOpen = path.join(pathToOpen, 'michelle-is-awesome.txt'); await atom.openLocations([ @@ -958,8 +898,6 @@ describe('AtomEnvironment', () => { atom.attemptRestoreProjectStateForPaths ).not.toHaveBeenCalledWith(state, [pathToOpen], [fileToOpen]); expect(atom.project.getPaths()).toEqual([__dirname, pathToOpen]); - - done(); }); }); }); diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index a3cfc2db0a..059ccafc77 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -41,14 +41,16 @@ describe('AtomPaths', () => { expect(process.env.ATOM_HOME).toEqual(portableAtomHomePath); }); - it('uses ATOM_HOME if no write access to portable .atom folder', () => { - jasmine.filterByPlatform({except: ['win32']}); + it('uses ATOM_HOME if no write access to portable .atom folder', (done) => { + jasmine.filterByPlatform({except: ['win32']}, done); const readOnlyPath = temp.mkdirSync('atom-path-spec-no-write-access'); process.env.ATOM_HOME = readOnlyPath; fs.chmodSync(portableAtomHomePath, 444); atomPaths.setAtomHome(app.getPath('home')); expect(process.env.ATOM_HOME).toEqual(readOnlyPath); + + done(); }); }); @@ -119,14 +121,16 @@ describe('AtomPaths', () => { expect(app.getPath('userData')).toEqual(electronUserDataPath); }); - it('leaves userData unchanged if no write access to electronUserData folder', () => { - jasmine.filterByPlatform({except: ['win32']}); + it('leaves userData unchanged if no write access to electronUserData folder', (done) => { + jasmine.filterByPlatform({except: ['win32']}, done); fs.mkdirSync(electronUserDataPath); fs.chmodSync(electronUserDataPath, 444); atomPaths.setUserData(app); fs.chmodSync(electronUserDataPath, 666); expect(app.getPath('userData')).toEqual(defaultElectronUserDataPath); + + done(); }); }); diff --git a/spec/buffered-node-process-spec.js b/spec/buffered-node-process-spec.js index af71fa20f6..e38b03b216 100644 --- a/spec/buffered-node-process-spec.js +++ b/spec/buffered-node-process-spec.js @@ -3,7 +3,7 @@ const path = require('path'); const BufferedNodeProcess = require('../src/buffered-node-process'); describe('BufferedNodeProcess', function() { - it('executes the script in a new process', async function(done) { + it('executes the script in a new process', async function() { let output = ''; const stdout = lines => (output += lines); let error = ''; @@ -18,11 +18,9 @@ describe('BufferedNodeProcess', function() { expect(output).toBe('hi'); expect(error).toBe(''); expect(args).toEqual(['hi']); - - done(); }); - it('suppresses deprecations in the new process', async function(done) { + it('suppresses deprecations in the new process', async function() { const exit = jasmine.createSpy('exitCallback'); let output = ''; const stdout = lines => (output += lines); @@ -40,7 +38,5 @@ describe('BufferedNodeProcess', function() { expect(output).toBe('hi'); expect(error).toBe(''); - - done(); }); }); diff --git a/spec/buffered-process-spec.js b/spec/buffered-process-spec.js index 212c543610..41d81cfaed 100644 --- a/spec/buffered-process-spec.js +++ b/spec/buffered-process-spec.js @@ -14,7 +14,7 @@ describe('BufferedProcess', function() { describe('when there is an error handler specified', function() { describe('when an error event is emitted by the process', () => - it('calls the error handler and does not throw an exception', async function(done) { + it('calls the error handler and does not throw an exception', async function() { const bufferedProcess = new BufferedProcess({ command: 'bad-command-nope1', args: ['nothing'], @@ -36,12 +36,10 @@ describe('BufferedProcess', function() { expect(errorSpy.calls.mostRecent().args[0].error.message).toContain( 'spawn bad-command-nope1 ENOENT' ); - - done(); })); describe('when an error is thrown spawning the process', () => - it('calls the error handler and does not throw an exception', async function(done) { + it('calls the error handler and does not throw an exception', async function() { spyOn(ChildProcess, 'spawn').and.callFake(function() { const error = new Error('Something is really wrong'); error.code = 'EAGAIN'; @@ -69,13 +67,11 @@ describe('BufferedProcess', function() { expect(errorSpy.calls.mostRecent().args[0].error.message).toContain( 'Something is really wrong' ); - - done(); })); }); describe('when there is not an error handler specified', () => - it('does throw an exception', async function(done) { + it('does throw an exception', async function() { await new Promise((resolve) => { window.onerror.and.callFake(resolve); @@ -93,8 +89,6 @@ describe('BufferedProcess', function() { expect(window.onerror.calls.mostRecent().args[4].name).toBe( 'BufferedProcessError' ); - - done(); })); }); @@ -103,7 +97,7 @@ describe('BufferedProcess', function() { * TODO: FAILING TEST - This test fails with the following output: * timeout: timed out after 120000 msec waiting for condition */ - xit('doesnt start unless start method is called', async function(done) { + xit('doesnt start unless start method is called', async function() { let stdout = ''; let stderr = ''; const exitCallback = jasmine.createSpy('exit callback'); @@ -134,14 +128,12 @@ describe('BufferedProcess', function() { expect(stderr).toContain('apm - Atom Package Manager'); expect(stdout).toEqual(''); - - done(); })); /** * TODO: FAILING TEST - This test fails with the following output: * timeout: timed out after 120000 msec waiting for condition */ - xit('calls the specified stdout, stderr, and exit callbacks', async function(done) { + xit('calls the specified stdout, stderr, and exit callbacks', async function() { let stdout = ''; let stderr = ''; @@ -164,7 +156,7 @@ describe('BufferedProcess', function() { expect(stdout).toEqual(''); }); - it('calls the specified stdout callback with whole lines', async function(done) { + it('calls the specified stdout callback with whole lines', async function() { const exitCallback = jasmine.createSpy('exit callback'); const loremPath = require.resolve('./fixtures/lorem.txt'); const content = fs.readFileSync(loremPath).toString(); @@ -191,8 +183,6 @@ describe('BufferedProcess', function() { expect(allLinesEndWithNewline).toBe(true); expect(stdout).toBe(content); - - done(); }); describe('on Windows', function() { diff --git a/spec/command-registry-spec.js b/spec/command-registry-spec.js index 53be73fe76..1f170ef980 100644 --- a/spec/command-registry-spec.js +++ b/spec/command-registry-spec.js @@ -387,7 +387,7 @@ describe('CommandRegistry', () => { expect(registry.dispatch(parent, 'command')).toBe(null); }); - it('returns a promise that resolves when the listeners resolve', async (done) => { + 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)); @@ -404,10 +404,9 @@ describe('CommandRegistry', () => { const values = await registry.dispatch(grandchild, 'command'); expect(values).toEqual([3, 2, 1]); - done(); }); - it('returns a promise that rejects when a listener is rejected', async (done) => { + 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)); @@ -429,7 +428,6 @@ describe('CommandRegistry', () => { value = err; } expect(value).toBe(3); - done(); }); }); diff --git a/spec/config-file-spec.js b/spec/config-file-spec.js index ed2643cf56..bc229ed384 100644 --- a/spec/config-file-spec.js +++ b/spec/config-file-spec.js @@ -18,28 +18,24 @@ describe('ConfigFile', () => { }); describe('when the file does not exist', () => { - it('returns an empty object from .get()', async (done) => { + it('returns an empty object from .get()', async () => { configFile = new ConfigFile(filePath); subscription = await configFile.watch(); expect(configFile.get()).toEqual({}); - - done(); }); }); describe('when the file is empty', () => { - it('returns an empty object from .get()', async (done) => { + it('returns an empty object from .get()', async () => { writeFileSync(filePath, ''); configFile = new ConfigFile(filePath); subscription = await configFile.watch(); expect(configFile.get()).toEqual({}); - - done(); }); }); describe('when the file is updated with valid CSON', () => { - it('notifies onDidChange observers with the data', async (done) => { + it('notifies onDidChange observers with the data', async () => { configFile = new ConfigFile(filePath); subscription = await configFile.watch(); @@ -65,13 +61,11 @@ describe('ConfigFile', () => { '*': { foo: 'bar' }, javascript: { foo: 'baz' } }); - - done(); }); }); describe('when the file is updated with invalid CSON', () => { - it('notifies onDidError observers', async (done) => { + it('notifies onDidError observers', async () => { configFile = new ConfigFile(filePath); subscription = await configFile.watch(); @@ -105,8 +99,6 @@ describe('ConfigFile', () => { '*': { foo: 'bar' }, javascript: { foo: 'baz' } }); - - done(); }); }); diff --git a/spec/config-spec.js b/spec/config-spec.js index 1b7079a4cb..9a06fd4cec 100644 --- a/spec/config-spec.js +++ b/spec/config-spec.js @@ -1042,7 +1042,7 @@ describe('Config', () => { atom.config.onDidChange('foo.bar.baz', changeSpy); }); - it('allows only one change event for the duration of the given promise if it gets resolved', async (done) => { + it('allows only one change event for the duration of the given promise if it gets resolved', async () => { let promiseResult = null; const transactionPromise = atom.config.transactAsync(() => { atom.config.set('foo.bar.baz', 1); @@ -1059,11 +1059,9 @@ describe('Config', () => { newValue: 3, oldValue: undefined }); - - done(); }); - it('allows only one change event for the duration of the given promise if it gets rejected', async (done) => { + it('allows only one change event for the duration of the given promise if it gets rejected', async () => { let promiseError = null; const transactionPromise = atom.config.transactAsync(() => { atom.config.set('foo.bar.baz', 1); @@ -1082,11 +1080,9 @@ describe('Config', () => { newValue: 3, oldValue: undefined }); - - done(); }); - it('allows only one change event even when the given callback throws', async (done) => { + it('allows only one change event even when the given callback throws', async () => { const error = new Error('Oops!'); let promiseError = null; const transactionPromise = atom.config.transactAsync(() => { @@ -1106,8 +1102,6 @@ describe('Config', () => { newValue: 3, oldValue: undefined }); - - done(); }); }); diff --git a/spec/decoration-manager-spec.js b/spec/decoration-manager-spec.js index 0249e91b2b..fef8f67113 100644 --- a/spec/decoration-manager-spec.js +++ b/spec/decoration-manager-spec.js @@ -4,7 +4,7 @@ const TextEditor = require('../src/text-editor'); describe('DecorationManager', function() { let decorationManager, buffer, editor, markerLayer1, markerLayer2; - beforeEach(async function(done) { + beforeEach(async function() { buffer = atom.project.bufferForPathSync('sample.js'); editor = new TextEditor({ buffer }); markerLayer1 = editor.addMarkerLayer(); @@ -12,8 +12,6 @@ describe('DecorationManager', function() { decorationManager = new DecorationManager(editor); await atom.packages.activatePackage('language-javascript'); - - done(); }); afterEach(() => buffer.destroy()); diff --git a/spec/default-directory-provider-spec.js b/spec/default-directory-provider-spec.js index ffb2568ab5..0691938a4b 100644 --- a/spec/default-directory-provider-spec.js +++ b/spec/default-directory-provider-spec.js @@ -33,8 +33,8 @@ describe('DefaultDirectoryProvider', function() { expect(directory.getPath()).toEqual(tmp); }); - it('normalizes disk drive letter in path on win32', function() { - jasmine.filterByPlatform({only: ['win32']}); + it('normalizes disk drive letter in path on win32', function(done) { + jasmine.filterByPlatform({only: ['win32']}, done); const provider = new DefaultDirectoryProvider(); const nonNormalizedPath = tmp[0].toLowerCase() + tmp.slice(1); @@ -43,6 +43,8 @@ describe('DefaultDirectoryProvider', function() { const directory = provider.directoryForURISync(nonNormalizedPath); expect(directory.getPath()).toEqual(tmp); + + done() }); it('creates a Directory for its parent dir when passed a file', function() { @@ -63,12 +65,10 @@ describe('DefaultDirectoryProvider', function() { }); describe('.directoryForURI(uri)', () => - it('returns a Promise that resolves to a Directory with a path that matches the uri', async function(done) { + it('returns a Promise that resolves to a Directory with a path that matches the uri', async function() { const provider = new DefaultDirectoryProvider(); let directory = await provider.directoryForURI(tmp); expect(directory.getPath()).toEqual(tmp); - - done(); })); }); diff --git a/spec/default-directory-searcher-spec.js b/spec/default-directory-searcher-spec.js index e93e0d6a0b..715a34e474 100644 --- a/spec/default-directory-searcher-spec.js +++ b/spec/default-directory-searcher-spec.js @@ -11,7 +11,7 @@ describe('DefaultDirectorySearcher', function() { searcher = new DefaultDirectorySearcher(); }); - it('terminates the task after running a search', async function(done) { + it('terminates the task after running a search', async function() { const options = { ignoreCase: false, includeHidden: false, @@ -38,7 +38,5 @@ describe('DefaultDirectorySearcher', function() { ); expect(Task.prototype.terminate).toHaveBeenCalled(); - - done(); }); }); diff --git a/spec/dock-spec.js b/spec/dock-spec.js index 460ff30e04..8a8b6c4870 100644 --- a/spec/dock-spec.js +++ b/spec/dock-spec.js @@ -79,7 +79,7 @@ describe('Dock', () => { }); describe('when a pane in a dock is activated', () => { - it('opens the dock', async (done) => { + it('opens the dock', async () => { const item = { element: document.createElement('div'), getDefaultLocation() { @@ -95,8 +95,6 @@ describe('Dock', () => { .getPanes()[0] .activate(); expect(atom.workspace.getLeftDock().isVisible()).toBe(true); - - done(); }); }); @@ -166,7 +164,7 @@ 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 (done) => { + it("resizes a vertically-oriented dock to the current item's preferred width", async () => { jasmine.attachToDOM(atom.workspace.getElement()); const item = { @@ -195,11 +193,9 @@ describe('Dock', () => { await getNextUpdatePromise(); expect(dockElement.offsetWidth).toBe(item.getPreferredWidth()); - - done(); }); - it("resizes a horizontally-oriented dock to the current item's preferred width", async (done) => { + it("resizes a horizontally-oriented dock to the current item's preferred width", async () => { jasmine.attachToDOM(atom.workspace.getElement()); const item = { @@ -228,13 +224,11 @@ describe('Dock', () => { await getNextUpdatePromise(); expect(dockElement.offsetHeight).toBe(item.getPreferredHeight()); - - done(); }); }); describe('when the dock is closed', () => { - it('does nothing', async (done) => { + it('does nothing', async () => { jasmine.attachToDOM(atom.workspace.getElement()); const item = { @@ -264,15 +258,13 @@ describe('Dock', () => { expect(dockElement.querySelector('.atom-dock-mask').offsetHeight).toBe( 0 ); - - done(); }); }); }); describe('when you add an item to an empty dock', () => { describe('when the item has a preferred size', () => { - it('is takes the preferred size of the item', async (done) => { + it('is takes the preferred size of the item', async () => { jasmine.attachToDOM(atom.workspace.getElement()); const createItem = preferredWidth => ({ @@ -307,13 +299,11 @@ describe('Dock', () => { const item3 = createItem(333); await atom.workspace.open(item3); expect(dockElement.offsetWidth).toBe(222); - - done(); }); }); describe('when the item has no preferred size', () => { - it('is still has an explicit size', async (done) => { + it('is still has an explicit size', async () => { jasmine.attachToDOM(atom.workspace.getElement()); const item = { @@ -328,14 +318,12 @@ describe('Dock', () => { expect(dock.state.size).toBe(null); await atom.workspace.open(item); expect(dock.state.size).not.toBe(null); - - done(); }); }); }); describe('a deserialized dock', () => { - it('restores the serialized size', async (done) => { + it('restores the serialized size', async () => { jasmine.attachToDOM(atom.workspace.getElement()); const item = { @@ -364,11 +352,9 @@ describe('Dock', () => { dock.destroyActivePane(); dock.deserialize(serialized, atom.deserializers); expect(dockElement.offsetWidth).toBe(150); - - done(); }); - it("isn't visible if it has no items", async (done) => { + it("isn't visible if it has no items", async () => { jasmine.attachToDOM(atom.workspace.getElement()); const item = { @@ -388,13 +374,11 @@ describe('Dock', () => { dock.deserialize(serialized, atom.deserializers); expect(dock.getPaneItems()).toHaveLength(0); expect(dock.isVisible()).toBe(false); - - done(); }); }); describe('drag handling', () => { - it('expands docks to match the preferred size of the dragged item', async (done) => { + it('expands docks to match the preferred size of the dragged item', async () => { jasmine.attachToDOM(atom.workspace.getElement()); const element = document.createElement('div'); @@ -417,8 +401,6 @@ describe('Dock', () => { expect(atom.workspace.getLeftDock().refs.wrapperElement.offsetWidth).toBe( 144 ); - - done(); }); it('does nothing when text nodes are dragged', () => { diff --git a/spec/git-repository-provider-spec.js b/spec/git-repository-provider-spec.js index 52d100587b..413dfe67e1 100644 --- a/spec/git-repository-provider-spec.js +++ b/spec/git-repository-provider-spec.js @@ -26,7 +26,7 @@ describe('GitRepositoryProvider', () => { describe('.repositoryForDirectory(directory)', () => { describe('when specified a Directory with a Git repository', () => { - it('resolves with a GitRepository', async (done) => { + it('resolves with a GitRepository', async () => { const directory = new Directory( path.join(__dirname, 'fixtures', 'git', 'master.git') ); @@ -37,11 +37,9 @@ describe('GitRepositoryProvider', () => { // Refresh should be started await new Promise(resolve => result.onDidChangeStatuses(resolve)); - - done(); }); - it('resolves with the same GitRepository for different Directory objects in the same repo', async (done) => { + it('resolves with the same GitRepository for different Directory objects in the same repo', async () => { const firstRepo = await provider.repositoryForDirectory( new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git')) ); @@ -53,23 +51,19 @@ describe('GitRepositoryProvider', () => { expect(firstRepo).toEqual(jasmine.any(GitRepository)); expect(firstRepo).toBe(secondRepo); - - done(); }); }); describe('when specified a Directory without a Git repository', () => { - it('resolves with null', async (done) => { + it('resolves with null', async () => { const directory = new Directory(temp.mkdirSync('dir')); const repo = await provider.repositoryForDirectory(directory); expect(repo).toBe(null); - - done(); }); }); describe('when specified a Directory with an invalid Git repository', () => { - it('resolves with null', async (done) => { + it('resolves with null', async () => { const dirPath = temp.mkdirSync('dir'); fs.writeFileSync(path.join(dirPath, '.git', 'objects'), ''); fs.writeFileSync(path.join(dirPath, '.git', 'HEAD'), ''); @@ -78,13 +72,11 @@ describe('GitRepositoryProvider', () => { const directory = new Directory(dirPath); const repo = await provider.repositoryForDirectory(directory); expect(repo).toBe(null); - - done(); }); }); describe('when specified a Directory with a valid gitfile-linked repository', () => { - it('returns a Promise that resolves to a GitRepository', async (done) => { + it('returns a Promise that resolves to a GitRepository', async () => { const gitDirPath = path.join( __dirname, 'fixtures', @@ -102,13 +94,11 @@ describe('GitRepositoryProvider', () => { expect(result).toEqual(jasmine.any(GitRepository)); expect(provider.pathToRepository[result.getPath()]).toBeTruthy(); expect(result.getType()).toBe('git'); - - done(); }); }); describe('when specified a Directory with a commondir file for a worktree', () => { - it('returns a Promise that resolves to a GitRepository', async (done) => { + it('returns a Promise that resolves to a GitRepository', async () => { const directory = new Directory( path.join( __dirname, @@ -123,8 +113,6 @@ describe('GitRepositoryProvider', () => { expect(result).toEqual(jasmine.any(GitRepository)); expect(provider.pathToRepository[result.getPath()]).toBeTruthy(); expect(result.getType()).toBe('git'); - - done(); }); }); @@ -143,19 +131,17 @@ describe('GitRepositoryProvider', () => { spyOn(directory, 'getSubdirectory').and.returnValue(subdirectory); }); - it('returns a Promise that resolves to null', async (done) => { + it('returns a Promise that resolves to null', async () => { const repo = await provider.repositoryForDirectory(directory); expect(repo).toBe(null); expect(directory.getSubdirectory).toHaveBeenCalledWith('.git'); - - done(); }); }); }); describe('.repositoryForDirectorySync(directory)', () => { describe('when specified a Directory with a Git repository', () => { - it('resolves with a GitRepository', async (done) => { + it('resolves with a GitRepository', async () => { const directory = new Directory( path.join(__dirname, 'fixtures', 'git', 'master.git') ); @@ -166,8 +152,6 @@ describe('GitRepositoryProvider', () => { // Refresh should be started await new Promise(resolve => result.onDidChangeStatuses(resolve)); - - done(); }); it('resolves with the same GitRepository for different Directory objects in the same repo', () => { diff --git a/spec/git-repository-spec.js b/spec/git-repository-spec.js index f04c8d5628..3adba8945e 100644 --- a/spec/git-repository-spec.js +++ b/spec/git-repository-spec.js @@ -162,7 +162,7 @@ describe('GitRepository', () => { describe('.checkoutHeadForEditor(editor)', () => { let filePath, editor; - beforeEach(async (done) => { + beforeEach(async () => { spyOn(atom, 'confirm'); const workingDirPath = copyRepository(); @@ -175,12 +175,10 @@ describe('GitRepository', () => { fs.writeFileSync(filePath, 'ch ch changes'); editor = await atom.workspace.open(filePath); - - done(); }); - it('displays a confirmation dialog by default', () => { - jasmine.filterByPlatform({except: ['win32']}); // Permissions issues with this test on Windows + it('displays a confirmation dialog by default', (done) => { + jasmine.filterByPlatform({except: ['win32']}, done); // Permissions issues with this test on Windows atom.confirm.and.callFake(({ buttons }) => buttons.OK()); atom.config.set('editor.confirmCheckoutHeadRevision', true); @@ -188,10 +186,12 @@ describe('GitRepository', () => { repo.checkoutHeadForEditor(editor); expect(fs.readFileSync(filePath, 'utf8')).toBe(''); + + done(); }); - it('does not display a dialog when confirmation is disabled', () => { - jasmine.filterByPlatform({except: ['win32']}); // Flakey EPERM opening a.txt on Win32 + it('does not display a dialog when confirmation is disabled', (done) => { + jasmine.filterByPlatform({except: ['win32']}, done); // Flakey EPERM opening a.txt on Win32 atom.config.set('editor.confirmCheckoutHeadRevision', false); @@ -199,6 +199,8 @@ describe('GitRepository', () => { expect(fs.readFileSync(filePath, 'utf8')).toBe(''); expect(atom.confirm).not.toHaveBeenCalled(); + + done(); }); }); @@ -277,7 +279,7 @@ describe('GitRepository', () => { newPath = fs.absolute(newPath); }); - it('returns status information for all new and modified files', async (done) => { + it('returns status information for all new and modified files', async () => { const statusHandler = jasmine.createSpy('statusHandler'); repo.onDidChangeStatuses(statusHandler); fs.writeFileSync(modifiedPath, 'making this path modified'); @@ -289,11 +291,9 @@ describe('GitRepository', () => { expect( repo.isStatusModified(repo.getCachedPathStatus(modifiedPath)) ).toBeTruthy(); - - done(); }); - it('caches the proper statuses when a subdir is open', async (done) => { + it('caches the proper statuses when a subdir is open', async () => { const subDir = path.join(workingDirectory, 'dir'); fs.mkdirSync(subDir); const filePath = path.join(subDir, 'b.txt'); @@ -306,11 +306,9 @@ describe('GitRepository', () => { const status = repo.getCachedPathStatus(filePath); expect(repo.isStatusModified(status)).toBe(false); expect(repo.isStatusNew(status)).toBe(false); - - done(); }); - it('works correctly when the project has multiple folders (regression)', async (done) => { + it('works correctly when the project has multiple folders (regression)', async () => { atom.project.addPath(workingDirectory); atom.project.addPath(path.join(__dirname, 'fixtures', 'dir')); @@ -320,11 +318,9 @@ describe('GitRepository', () => { expect( repo.isStatusModified(repo.getCachedPathStatus(modifiedPath)) ).toBeTruthy(); - - done(); }); - it('caches statuses that were looked up synchronously', async (done) => { + it('caches statuses that were looked up synchronously', async () => { const originalContent = 'undefined'; fs.writeFileSync(modifiedPath, 'making this path modified'); repo.getPathStatus('file.txt'); @@ -334,26 +330,22 @@ describe('GitRepository', () => { expect( repo.isStatusModified(repo.getCachedPathStatus(modifiedPath)) ).toBeFalsy(); - - done(); }); }); describe('buffer events', () => { let editor; - beforeEach(async (done) => { + beforeEach(async () => { atom.project.setPaths([copyRepository()]); const refreshPromise = new Promise(resolve => atom.project.getRepositories()[0].onDidChangeStatuses(resolve) ); editor = await atom.workspace.open('other.txt'); await refreshPromise; - - done(); }); - it('emits a status-changed event when a buffer is saved', async (done) => { + it('emits a status-changed event when a buffer is saved', async () => { editor.insertNewline(); const statusHandler = jasmine.createSpy('statusHandler'); @@ -365,11 +357,9 @@ describe('GitRepository', () => { path: editor.getPath(), pathStatus: 256 }); - - done(); }); - it('emits a status-changed event when a buffer is reloaded', async (done) => { + it('emits a status-changed event when a buffer is reloaded', async () => { fs.writeFileSync(editor.getPath(), 'changed'); const statusHandler = jasmine.createSpy('statusHandler'); @@ -384,8 +374,6 @@ describe('GitRepository', () => { await editor.getBuffer().reload(); expect(statusHandler.calls.count()).toBe(1); - - done(); }); it("emits a status-changed event when a buffer's path changes", () => { @@ -416,7 +404,7 @@ describe('GitRepository', () => { if (project2) project2.destroy(); }); - it('subscribes to all the serialized buffers in the project', async (done) => { + it('subscribes to all the serialized buffers in the project', async () => { atom.project.setPaths([copyRepository()]); await atom.workspace.open('file.txt'); @@ -444,8 +432,6 @@ describe('GitRepository', () => { path: buffer.getPath(), pathStatus: 256 }); - - done(); }); }); }); diff --git a/spec/grammar-registry-spec.js b/spec/grammar-registry-spec.js index e9fc4f5046..396227e990 100644 --- a/spec/grammar-registry-spec.js +++ b/spec/grammar-registry-spec.js @@ -19,16 +19,14 @@ function setConfigForLanguageMode(mode, options = {}) { describe('GrammarRegistry', () => { let grammarRegistry; - beforeEach(async (done) => { + beforeEach(async () => { await SecondMate.ready grammarRegistry = new GrammarRegistry({ config: atom.config }); expect(subscriptionCount(grammarRegistry)).toBe(2); - - done(); }); describe('.assignLanguageMode(buffer, languageId)', () => { - it('assigns to the buffer a language mode with the given language id', async (done) => { + it('assigns to the buffer a language mode with the given language id', async () => { grammarRegistry.loadGrammarSync( require.resolve('language-javascript/grammars/javascript.cson') ); @@ -57,8 +55,6 @@ describe('GrammarRegistry', () => { // Returns false if no language is found expect(grammarRegistry.assignLanguageMode(buffer, 'blub')).toBe(false); expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css'); - - done(); }); describe('when no languageId is passed', () => { @@ -181,7 +177,7 @@ describe('GrammarRegistry', () => { }); describe('.maintainLanguageMode(buffer)', () => { - it('assigns a grammar to the buffer based on its path', async (done) => { + it('assigns a grammar to the buffer based on its path', async () => { const buffer = new TextBuffer(); grammarRegistry.loadGrammarSync( @@ -197,11 +193,9 @@ describe('GrammarRegistry', () => { buffer.setPath('test.c'); expect(buffer.getLanguageMode().getLanguageId()).toBe('source.c'); - - done(); }); - it("updates the buffer's grammar when a more appropriate text-mate grammar is added for its path", async (done) => { + it("updates the buffer's grammar when a more appropriate text-mate grammar is added for its path", async () => { setConfigForLanguageMode('textmate'); const buffer = new TextBuffer(); @@ -221,11 +215,9 @@ describe('GrammarRegistry', () => { ) ); expect(buffer.getLanguageMode().grammar).toBe(textMateGrammar); - - done(); }); - it("updates the buffer's grammar when a more appropriate tree-sitter grammar is added for its path", async (done) => { + it("updates the buffer's grammar when a more appropriate tree-sitter grammar is added for its path", async () => { setConfigForLanguageMode('node-tree-sitter'); const buffer = new TextBuffer(); @@ -245,11 +237,9 @@ describe('GrammarRegistry', () => { require.resolve('language-javascript/grammars/javascript.cson') ); expect(buffer.getLanguageMode().grammar).toBe(treeSitterGrammar); - - done(); }); - it("updates the buffer's grammar when a more appropriate new-tree-sitter grammar is added for its path and the user has opted into new-tree-sitter", async (done) => { + it("updates the buffer's grammar when a more appropriate new-tree-sitter grammar is added for its path and the user has opted into new-tree-sitter", async () => { setConfigForLanguageMode('wasm-tree-sitter'); const buffer = new TextBuffer(); @@ -276,11 +266,9 @@ describe('GrammarRegistry', () => { require.resolve('language-javascript/grammars/javascript.cson') ); expect(buffer.getLanguageMode().grammar).toBe(modernTreeSitterGrammar); - - done(); }); - it("updates the buffer's grammar by ignoring a new-tree-sitter grammar if the user has NOT opted into new-tree-sitter", async (done) => { + it("updates the buffer's grammar by ignoring a new-tree-sitter grammar if the user has NOT opted into new-tree-sitter", async () => { setConfigForLanguageMode('node-tree-sitter'); const buffer = new TextBuffer(); @@ -310,7 +298,6 @@ describe('GrammarRegistry', () => { ); expect(buffer.getLanguageMode().grammar).toBe(treeSitterGrammar); - done(); }); @@ -334,7 +321,7 @@ describe('GrammarRegistry', () => { expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css'); }); - it('returns a disposable that can be used to stop the registry from updating the buffer', async (done) => { + 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') @@ -366,10 +353,9 @@ describe('GrammarRegistry', () => { 'text.plain.null-grammar' ); expect(retainedBufferCount(grammarRegistry)).toBe(0); - done(); }); - it("doesn't do anything when called a second time with the same buffer", async (done) => { + 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') @@ -391,7 +377,6 @@ describe('GrammarRegistry', () => { expect(buffer.getLanguageMode().getLanguageId()).toBe( 'text.plain.null-grammar' ); - done(); }); it('does not retain the buffer after the buffer is destroyed', () => { @@ -440,15 +425,14 @@ describe('GrammarRegistry', () => { ); }); - it('selects the text.plain grammar over the null grammar', async (done) => { + 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' ); - done(); }); - it('selects a grammar based on the file path case insensitively', async (done) => { + 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' @@ -456,7 +440,6 @@ describe('GrammarRegistry', () => { expect(atom.grammars.selectGrammar('/tmp/source.COFFEE').scopeName).toBe( 'source.coffee' ); - done(); }); describe('on Windows', () => { @@ -471,16 +454,15 @@ describe('GrammarRegistry', () => { Object.defineProperty(process, 'platform', { value: originalPlatform }); }); - it('normalizes back slashes to forward slashes when matching the fileTypes', async (done) => { + 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'); - done(); }); }); - it("can use the filePath to load the correct grammar based on the grammar's filetype", async (done) => { + it("can use the filePath to load the correct grammar based on the grammar's filetype", async () => { await atom.packages.activatePackage('language-git'); await atom.packages.activatePackage('language-javascript'); await atom.packages.activatePackage('language-ruby'); @@ -494,28 +476,25 @@ describe('GrammarRegistry', () => { expect(atom.grammars.selectGrammar('/hu.git/config').name).toBe( 'Null Grammar' ); - done(); }); - it(`returns a legacy Tree-sitter grammar if the user opted into it via a scope-specific setting`, async (done) => { + it(`returns a legacy Tree-sitter grammar if the user opted into it via a scope-specific setting`, async () => { await atom.packages.activatePackage('language-javascript'); setConfigForLanguageMode('node-tree-sitter', { scopeSelector: '.source.js' }) let grammar = atom.grammars.selectGrammar('file.js'); expect(grammar.name).toBe('JavaScript'); expect(grammar.constructor.name).toBe('TreeSitterGrammar'); - done(); }) - it("uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", async (done) => { + it("uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", async () => { await atom.packages.activatePackage('language-javascript'); await atom.packages.activatePackage('language-ruby'); const filePath = require.resolve('./fixtures/shebang'); expect(atom.grammars.selectGrammar(filePath).name).toBe('Ruby'); - done(); }); - it('uses the number of newlines in the first line regex to determine the number of lines to test against', async (done) => { + it('uses the number of newlines in the first line regex to determine the number of lines to test against', async () => { await atom.packages.activatePackage('language-property-list'); await atom.packages.activatePackage('language-coffee-script'); @@ -534,10 +513,9 @@ describe('GrammarRegistry', () => { expect( atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name ).toBe('Property List (XML)'); - done(); }); - it("doesn't read the file when the file contents are specified", async (done) => { + it("doesn't read the file when the file contents are specified", async () => { await atom.packages.activatePackage('language-ruby'); const filePath = require.resolve('./fixtures/shebang'); @@ -547,7 +525,6 @@ describe('GrammarRegistry', () => { 'Ruby' ); expect(fs.read).not.toHaveBeenCalled(); - done(); }); describe('when multiple grammars have matching fileTypes', () => { @@ -580,7 +557,7 @@ describe('GrammarRegistry', () => { }); }); - it('favors non-bundled packages when breaking scoring ties', async (done) => { + 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') @@ -597,7 +574,6 @@ describe('GrammarRegistry', () => { .scopeName ).toBe('test.rb'); expect(atom.grammars.selectGrammar('test.rb').scopeName).toBe('test.rb'); - done(); }); describe('when there is no file path', () => { @@ -611,7 +587,7 @@ 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 (done) => { + 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'] @@ -620,10 +596,9 @@ describe('GrammarRegistry', () => { atom.grammars.selectGrammar('build/Cheffile', 'cookbook "postgres"') .scopeName ).toBe('source.ruby'); - done(); }); - it('favors user-defined file types over built-in ones of equal length', async (done) => { + it('favors user-defined file types over built-in ones of equal length', async () => { await atom.packages.activatePackage('language-ruby'); await atom.packages.activatePackage('language-coffee-script'); @@ -637,10 +612,9 @@ describe('GrammarRegistry', () => { expect(atom.grammars.selectGrammar('Cakefile', '').scopeName).toBe( 'source.ruby' ); - done(); }); - it('favors user-defined file types over grammars with matching first-line-regexps', async (done) => { + 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'); @@ -651,17 +625,15 @@ describe('GrammarRegistry', () => { atom.grammars.selectGrammar('bootstrap', '#!/usr/bin/env node') .scopeName ).toBe('source.ruby'); - done(); }); }); - it('favors a grammar with a matching file type over one with m matching first line pattern', async (done) => { + 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'); - done(); }); describe('tree-sitter vs text-mate', () => { @@ -907,7 +879,7 @@ describe('GrammarRegistry', () => { }); describe('.removeGrammar(grammar)', () => { - it("removes the grammar, so it won't be returned by selectGrammar", async (done) => { + it("removes the grammar, so it won't be returned by selectGrammar", async () => { await atom.packages.activatePackage('language-css'); const grammar = atom.grammars.selectGrammar('foo.css'); atom.grammars.removeGrammar(grammar); @@ -916,7 +888,6 @@ describe('GrammarRegistry', () => { grammar.name === newGrammar.name && grammar.constructor.name === newGrammar.constructor.name ).toBe(false); - done(); }); }); @@ -947,17 +918,16 @@ describe('GrammarRegistry', () => { updateCallbackDisposable?.dispose(); }); - it('adds an injection point to the grammar with the given id', async (done) => { + it('adds an injection point to the grammar with the given id', async () => { await atom.packages.activatePackage('language-javascript'); atom.grammars.addInjectionPoint('source.js', injectionPoint); const grammar = atom.grammars.grammarForId('source.js'); expect( grammar.injectionPointsByType['some_node_type'] ).toContain(injectionPoint); - done(); }); - it('fires the onDidUpdateGrammar callback', async (done) => { + it('fires the onDidUpdateGrammar callback', async () => { await atom.packages.activatePackage('language-javascript'); let callbackDisposable = atom.grammars.onDidUpdateGrammar((grammar) => { if (grammar.scopeName === 'source.js') { @@ -966,11 +936,10 @@ describe('GrammarRegistry', () => { }); atom.grammars.addInjectionPoint('source.js', injectionPoint); expect(updateCallbackFired).toBe(true); - done(); }); describe('when called before a grammar with the given id is loaded', () => { - it('adds the injection point once the grammar is loaded', async (done) => { + it('adds the injection point once the grammar is loaded', async () => { // Adding an injection point before a grammar loads should not trigger // onDidUpdateGrammar at any point. updateCallbackDisposable = atom.grammars.onDidUpdateGrammar((grammar) => { @@ -992,13 +961,12 @@ describe('GrammarRegistry', () => { ).toContain(injectionPoint); expect(updateCallbackFired).toBe(false); expect(addCallbackFired).toBe(true); - done(); }); }); }); describe('serialization', () => { - it("persists editors' grammar overrides", async (done) => { + it("persists editors' grammar overrides", async () => { const buffer1 = new TextBuffer(); const buffer2 = new TextBuffer(); @@ -1045,33 +1013,29 @@ describe('GrammarRegistry', () => { ); expect(buffer1Copy.getLanguageMode().getLanguageId()).toBe('source.c'); expect(buffer2Copy.getLanguageMode().getLanguageId()).toBe('source.js'); - done(); }); }); describe('when working with grammars', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('language-javascript'); - done(); }); - it('returns only Tree-sitter grammars by default', async (done) => { + it('returns only Tree-sitter grammars by default', async () => { const tmGrammars = atom.grammars.getGrammars(); const allGrammars = atom.grammars.getGrammars({ includeTreeSitter: true }); expect(allGrammars.length).toBeGreaterThan(tmGrammars.length); - done(); }); - it('executes the foreach callback on both Tree-sitter and TextMate grammars', async (done) => { + it('executes the foreach callback on both Tree-sitter and TextMate grammars', async () => { const numAllGrammars = atom.grammars.getGrammars({ includeTreeSitter: true }).length; let i = 0; atom.grammars.forEachGrammar(() => i++); expect(i).toBe(numAllGrammars); - done(); }); }); }); diff --git a/spec/helpers/jasmine2-singleton.js b/spec/helpers/jasmine2-singleton.js index 1ffa1b6401..12b1f0576f 100644 --- a/spec/helpers/jasmine2-singleton.js +++ b/spec/helpers/jasmine2-singleton.js @@ -1,9 +1,6 @@ let Jasmine = require('jasmine'); let jasmine = new Jasmine(); -for (let key in jasmine.env) { - window[key] = jasmine.env[key]; -} window['jasmine'] = jasmine.jasmine module.exports = jasmine; diff --git a/spec/helpers/platform-filter.js b/spec/helpers/platform-filter.js index 538c4d86b1..6a9fc8a1d0 100644 --- a/spec/helpers/platform-filter.js +++ b/spec/helpers/platform-filter.js @@ -1,11 +1,11 @@ jasmine.filterByPlatform = ({only, except}, done) => { if (only && !only.includes(process.platform)) { - if (done) done(); + done(); pending(); } if (except && except.includes(process.platform)) { - if (done) done(); + done(); pending(); } } diff --git a/spec/history-manager-spec.js b/spec/history-manager-spec.js index b813b7c2b9..0687c3405b 100644 --- a/spec/history-manager-spec.js +++ b/spec/history-manager-spec.js @@ -5,7 +5,7 @@ describe('HistoryManager', () => { let historyManager, commandRegistry, project, stateStore; let commandDisposable, projectDisposable; - beforeEach(async (done) => { + beforeEach(async () => { commandDisposable = jasmine.createSpyObj('Disposable', ['dispose']); commandRegistry = jasmine.createSpyObj('CommandRegistry', ['add']); commandRegistry.add.and.returnValue(commandDisposable); @@ -34,12 +34,10 @@ describe('HistoryManager', () => { commands: commandRegistry }); await historyManager.loadState(); - done(); }); - afterEach(async (done) => { + afterEach(async () => { await stateStore.clear(); - done(); }); describe('constructor', () => { @@ -76,14 +74,13 @@ describe('HistoryManager', () => { }); describe('clearProjects', () => { - it('clears the list of projects', async (done) => { + it('clears the list of projects', async () => { expect(historyManager.getProjects().length).not.toBe(0); await historyManager.clearProjects(); expect(historyManager.getProjects().length).toBe(0); - done(); }); - it('saves the state', async (done) => { + it('saves the state', async () => { await historyManager.clearProjects(); const historyManager2 = new HistoryManager({ stateStore, @@ -92,16 +89,14 @@ describe('HistoryManager', () => { }); await historyManager2.loadState(); expect(historyManager.getProjects().length).toBe(0); - done(); }); - it('fires the onDidChangeProjects event', async (done) => { + it('fires the onDidChangeProjects event', async () => { const didChangeSpy = jasmine.createSpy(); historyManager.onDidChangeProjects(didChangeSpy); await historyManager.clearProjects(); expect(historyManager.getProjects().length).toBe(0); expect(didChangeSpy).toHaveBeenCalled(); - done(); }); }); @@ -125,70 +120,63 @@ describe('HistoryManager', () => { }); describe('loadState', () => { - it('defaults to an empty array if no state', async (done) => { + it('defaults to an empty array if no state', async () => { await stateStore.clear(); await historyManager.loadState(); expect(historyManager.getProjects()).toEqual([]); - done(); }); - it('defaults to an empty array if no projects', async (done) => { + it('defaults to an empty array if no projects', async () => { await stateStore.save('history-manager', {}); await historyManager.loadState(); expect(historyManager.getProjects()).toEqual([]); - done(); }); }); describe('addProject', () => { - it('adds a new project to the end', async (done) => { + 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(); expect(projects.length).toBe(3); expect(projects[2].paths).toEqual(['/a/b']); expect(projects[2].lastOpened).toBe(date); - done(); }); - it('adds a new project to the start', async (done) => { + it('adds a new project to the start', async () => { const date = new Date(); await historyManager.addProject(['/so/new'], date); const projects = historyManager.getProjects(); expect(projects.length).toBe(3); expect(projects[0].paths).toEqual(['/so/new']); expect(projects[0].lastOpened).toBe(date); - done(); }); - it('updates an existing project and moves it to the start', async (done) => { + 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(); expect(projects.length).toBe(2); expect(projects[0].paths).toEqual(['/test']); expect(projects[0].lastOpened).toBe(date); - done(); }); - it('fires the onDidChangeProjects event when adding a project', async (done) => { + it('fires the onDidChangeProjects event when adding a project', async () => { const didChangeSpy = jasmine.createSpy(); const beforeCount = historyManager.getProjects().length; historyManager.onDidChangeProjects(didChangeSpy); await historyManager.addProject(['/test-new'], new Date()); expect(didChangeSpy).toHaveBeenCalled(); expect(historyManager.getProjects().length).toBe(beforeCount + 1); - done(); }); - it('fires the onDidChangeProjects event when updating a project', async (done) => { + it('fires the onDidChangeProjects event when updating a project', async () => { const didChangeSpy = jasmine.createSpy(); const beforeCount = historyManager.getProjects().length; historyManager.onDidChangeProjects(didChangeSpy); await historyManager.addProject(['/test'], new Date()); expect(didChangeSpy).toHaveBeenCalled(); expect(historyManager.getProjects().length).toBe(beforeCount); - done(); }); }); @@ -220,7 +208,7 @@ describe('HistoryManager', () => { }); }); - it('saves the state', async (done) => { + it('saves the state', async () => { await historyManager.addProject(['/save/state']); await historyManager.saveState(); const historyManager2 = new HistoryManager({ @@ -233,7 +221,6 @@ describe('HistoryManager', () => { ); await historyManager2.loadState(); expect(historyManager2.getProjects()[0].paths).toEqual(['/save/state']); - done(); }); }); }); diff --git a/spec/native-watcher-registry-spec.js b/spec/native-watcher-registry-spec.js index 58926c20a6..a0475beffe 100644 --- a/spec/native-watcher-registry-spec.js +++ b/spec/native-watcher-registry-spec.js @@ -89,7 +89,7 @@ describe('NativeWatcherRegistry', function() { ); }); - it('attaches a Watcher to a newly created NativeWatcher for a new directory', async function(done) { + it('attaches a Watcher to a newly created NativeWatcher for a new directory', async function() { const watcher = new MockWatcher(absolute('some', 'path')); const NATIVE = new MockNative('created'); createNative = () => NATIVE; @@ -97,11 +97,9 @@ describe('NativeWatcherRegistry', function() { await registry.attach(watcher); expect(watcher.native).toBe(NATIVE); - - done(); }); - it('reuses an existing NativeWatcher on the same directory', async function(done) { + it('reuses an existing NativeWatcher on the same directory', async function() { // this.RETRY_FLAKY_TEST_AND_SLOW_DOWN_THE_BUILD(); const EXISTING = new MockNative('existing'); @@ -121,11 +119,9 @@ describe('NativeWatcherRegistry', function() { await registry.attach(watcher); expect(watcher.native).toBe(EXISTING); - - done(); }); - it('attaches to an existing NativeWatcher on a parent directory', async function(done) { + it('attaches to an existing NativeWatcher on a parent directory', async function() { const EXISTING = new MockNative('existing'); const parentDir = absolute('existing', 'path'); const subDir = path.join(parentDir, 'sub', 'directory'); @@ -144,10 +140,9 @@ describe('NativeWatcherRegistry', function() { await registry.attach(watcher); expect(watcher.native).toBe(EXISTING); - done(); }); - it('adopts Watchers from NativeWatchers on child directories', async function(done) { + it('adopts Watchers from NativeWatchers on child directories', async function() { const parentDir = absolute('existing', 'path'); const childDir0 = path.join(parentDir, 'child', 'directory', 'zero'); const childDir1 = path.join(parentDir, 'child', 'directory', 'one'); @@ -202,12 +197,10 @@ describe('NativeWatcherRegistry', function() { expect(watcher2.native).toBe(OTHER); expect(OTHER.stopped).toBe(false); expect(OTHER.disposed).toBe(false); - - done(); }); describe('removing NativeWatchers', function() { - it('happens when they stop', async function(done) { + it('happens when they stop', async function() { const STOPPED = new MockNative('stopped'); const RUNNING = new MockNative('running'); @@ -259,11 +252,9 @@ describe('NativeWatcherRegistry', function() { children: () => false }); expect(stoppedNode).toBe(true); - - done(); }); - it('reassigns new child watchers when a parent watcher is stopped', async function(done) { + it('reassigns new child watchers when a parent watcher is stopped', async function() { const CHILD0 = new MockNative('child0'); const CHILD1 = new MockNative('child1'); const PARENT = new MockNative('parent'); @@ -328,11 +319,9 @@ describe('NativeWatcherRegistry', function() { children: () => false }) ).toBe(true); - - done(); }); - it('consolidates children when splitting a parent watcher', async function(done) { + it('consolidates children when splitting a parent watcher', async function() { const CHILD0 = new MockNative('child0'); const PARENT = new MockNative('parent'); @@ -395,8 +384,6 @@ describe('NativeWatcherRegistry', function() { children: () => false }) ).toBe(true); - - done(); }); }); }); diff --git a/spec/package-manager-spec.js b/spec/package-manager-spec.js index 8751a29434..60369fd388 100644 --- a/spec/package-manager-spec.js +++ b/spec/package-manager-spec.js @@ -81,10 +81,9 @@ describe('PackageManager', () => { describe('::loadPackages()', () => { beforeEach(() => spyOn(atom.packages, 'loadAvailablePackage')); - afterEach(async (done) => { + afterEach(async () => { await atom.packages.deactivatePackages(); atom.packages.unloadPackages(); - done(); }); it('sets hasLoadedInitialPackages', () => { @@ -229,10 +228,9 @@ describe('PackageManager', () => { const model1 = { worksWithViewProvider1: true }; const model2 = { worksWithViewProvider2: true }; - afterEach(async (done) => { + afterEach(async () => { await atom.packages.deactivatePackage('package-with-view-providers'); atom.packages.unloadPackage('package-with-view-providers'); - done(); }); it('does not load the view providers immediately', () => { @@ -243,7 +241,7 @@ describe('PackageManager', () => { expect(() => atom.views.getView(model2)).toThrow(); }); - it('registers the view providers when the package is activated', async (done) => { + it('registers the view providers when the package is activated', async () => { atom.packages.loadPackage('package-with-view-providers'); await atom.packages.activatePackage('package-with-view-providers'); @@ -255,7 +253,6 @@ describe('PackageManager', () => { const element2 = atom.views.getView(model2); expect(element2 instanceof HTMLDivElement).toBe(true); expect(element2.dataset.createdBy).toBe('view-provider-2'); - done(); }); it("registers the view providers when any of the package's deserializers are used", () => { @@ -558,7 +555,7 @@ describe('PackageManager', () => { describe('::unloadPackage(name)', () => { describe('when the package is active', () => { - it('throws an error', async (done) => { + it('throws an error', async () => { const pack = await atom.packages.activatePackage('package-with-main'); expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy(); expect(atom.packages.isPackageActive(pack.name)).toBeTruthy(); @@ -566,7 +563,6 @@ describe('PackageManager', () => { expect(() => atom.packages.unloadPackage(pack.name)).toThrow(); expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy(); expect(atom.packages.isPackageActive(pack.name)).toBeTruthy(); - done(); }); }); @@ -600,14 +596,13 @@ describe('PackageManager', () => { describe('::activatePackage(id)', () => { describe('when called multiple times', () => { - it('it only calls activate on the package once', async (done) => { + it('it only calls activate on the package once', async () => { spyOn(Package.prototype, 'activateNow').and.callThrough(); await atom.packages.activatePackage('package-with-index'); await atom.packages.activatePackage('package-with-index'); await atom.packages.activatePackage('package-with-index'); expect(Package.prototype.activateNow.calls.count()).toBe(1); - done(); }); }); @@ -617,19 +612,18 @@ describe('PackageManager', () => { }); describe('when the metadata specifies a main module path˜', () => { - it('requires the module at the specified path', async (done) => { + it('requires the module at the specified path', async () => { const mainModule = require('./fixtures/packages/package-with-main/main-module'); spyOn(mainModule, 'activate'); const pack = await atom.packages.activatePackage('package-with-main'); expect(mainModule.activate).toHaveBeenCalled(); expect(pack.mainModule).toBe(mainModule); - done(); }); }); describe('when the metadata does not specify a main module', () => { - it('requires index.coffee', async (done) => { + it('requires index.coffee', async () => { const indexModule = require('./fixtures/packages/package-with-index/index'); spyOn(indexModule, 'activate'); @@ -638,11 +632,10 @@ describe('PackageManager', () => { ); expect(indexModule.activate).toHaveBeenCalled(); expect(pack.mainModule).toBe(indexModule); - done(); }); }); - it('assigns config schema, including defaults when package contains a schema', async (done) => { + it('assigns config schema, including defaults when package contains a schema', async () => { expect( atom.config.get('package-with-config-schema.numbers.one') ).toBeUndefined(); @@ -663,7 +656,6 @@ describe('PackageManager', () => { expect(atom.config.get('package-with-config-schema.numbers.one')).toBe( 10 ); - done(); }); describe('when the package metadata includes `activationCommands`', () => { @@ -696,7 +688,7 @@ describe('PackageManager', () => { mainModule = null; }); - it('defers requiring/activating the main module until an activation event bubbles to the root view', async (done) => { + it('defers requiring/activating the main module until an activation event bubbles to the root view', async () => { expect(Package.prototype.requireMainModule.calls.count()).toBe(0); atom.workspace @@ -707,10 +699,9 @@ describe('PackageManager', () => { await promise; expect(Package.prototype.requireMainModule.calls.count()).toBe(1); - done(); }); - it('triggers the activation event on all handlers registered during activation', async (done) => { + it('triggers the activation event on all handlers registered during activation', async () => { await atom.workspace.open(); const editorElement = atom.workspace @@ -736,11 +727,9 @@ describe('PackageManager', () => { expect(editorCommandListener.calls.count()).toBe(2); expect(workspaceCommandListener.calls.count()).toBe(2); expect(mainModule.activate.calls.count()).toBe(1); - - done(); }); - it('activates the package immediately when the events are empty', async (done) => { + it('activates the package immediately when the events are empty', async () => { mainModule = require('./fixtures/packages/package-with-empty-activation-commands/index'); spyOn(mainModule, 'activate').and.callThrough(); @@ -749,8 +738,6 @@ describe('PackageManager', () => { ); expect(mainModule.activate.calls.count()).toBe(1); - - done(); }); it('adds a notification when the activation commands are invalid', () => { @@ -787,7 +774,7 @@ describe('PackageManager', () => { ); }); - it('adds a notification when the grammar is invalid', async (done) => { + it('adds a notification when the grammar is invalid', async () => { let notificationEvent; await new Promise(resolve => { @@ -808,11 +795,9 @@ describe('PackageManager', () => { expect(notificationEvent.options.packageName).toEqual( 'package-with-invalid-grammar' ); - - done(); }); - it('adds a notification when the settings are invalid', async (done) => { + it('adds a notification when the settings are invalid', async () => { let notificationEvent; await new Promise(resolve => { @@ -833,8 +818,6 @@ describe('PackageManager', () => { expect(notificationEvent.options.packageName).toEqual( 'package-with-invalid-settings' ); - - done(); }); }); @@ -868,7 +851,7 @@ describe('PackageManager', () => { mainModule = null; }); - it('activates the package when a deserializer is called', async (done) => { + it('activates the package when a deserializer is called', async () => { expect(Package.prototype.requireMainModule.calls.count()).toBe(0); const state1 = { deserializer: 'Deserializer1', a: 'b' }; @@ -879,11 +862,9 @@ describe('PackageManager', () => { await promise; expect(Package.prototype.requireMainModule.calls.count()).toBe(1); - - done(); }); - it('defers requiring/activating the main module until an activation event bubbles to the root view', async (done) => { + it('defers requiring/activating the main module until an activation event bubbles to the root view', async () => { expect(Package.prototype.requireMainModule.calls.count()).toBe(0); atom.workspace @@ -896,8 +877,6 @@ describe('PackageManager', () => { expect(mainModule.activate.calls.count()).toBe(1); expect(mainModule.activationCommandCallCount).toBe(1); expect(Package.prototype.requireMainModule.calls.count()).toBe(1); - - done(); }); }); @@ -909,7 +888,7 @@ describe('PackageManager', () => { spyOn(mainModule, 'activate').and.callThrough(); }); - it('defers requiring/activating the main module until an triggering of an activation hook occurs', async (done) => { + it('defers requiring/activating the main module until an triggering of an activation hook occurs', async () => { promise = atom.packages.activatePackage( 'package-with-activation-hooks' ); @@ -921,11 +900,9 @@ describe('PackageManager', () => { await promise; expect(Package.prototype.requireMainModule.calls.count()).toBe(1); - - done(); }); - it('does not double register activation hooks when deactivating and reactivating', async (done) => { + it('does not double register activation hooks when deactivating and reactivating', async () => { promise = atom.packages.activatePackage( 'package-with-activation-hooks' ); @@ -952,11 +929,9 @@ describe('PackageManager', () => { await promise; expect(mainModule.activate.calls.count()).toBe(2); - - done(); }); - it('activates the package immediately when activationHooks is empty', async (done) => { + it('activates the package immediately when activationHooks is empty', async () => { mainModule = require('./fixtures/packages/package-with-empty-activation-hooks/index'); spyOn(mainModule, 'activate').and.callThrough(); @@ -967,11 +942,9 @@ describe('PackageManager', () => { ); expect(mainModule.activate.calls.count()).toBe(1); expect(Package.prototype.requireMainModule.calls.count()).toBe(1); - - done(); }); - it('activates the package immediately if the activation hook had already been triggered', async (done) => { + it('activates the package immediately if the activation hook had already been triggered', async () => { atom.packages.triggerActivationHook( 'language-fictitious:grammar-used' ); @@ -981,8 +954,6 @@ describe('PackageManager', () => { await atom.packages.activatePackage('package-with-activation-hooks'); expect(mainModule.activate.calls.count()).toBe(1); expect(Package.prototype.requireMainModule.calls.count()).toBe(1); - - done(); }); }); @@ -994,7 +965,7 @@ describe('PackageManager', () => { spyOn(mainModule, 'activate').and.callThrough(); }); - it('defers requiring/activating the main module until a registered opener is called', async (done) => { + it('defers requiring/activating the main module until a registered opener is called', async () => { promise = atom.packages.activatePackage( 'package-with-workspace-openers' ); @@ -1004,19 +975,15 @@ describe('PackageManager', () => { await promise; expect(Package.prototype.requireMainModule.calls.count()).toBe(1); expect(mainModule.openerCount).toBe(1); - - done(); }); - it('activates the package immediately when the events are empty', async (done) => { + it('activates the package immediately when the events are empty', async () => { mainModule = require('./fixtures/packages/package-with-empty-workspace-openers/index'); spyOn(mainModule, 'activate').and.callThrough(); atom.packages.activatePackage('package-with-empty-workspace-openers'); expect(mainModule.activate.calls.count()).toBe(1); - - done(); }); }); }); @@ -1034,16 +1001,14 @@ describe('PackageManager', () => { }); describe('when the package does not export an activate function', () => { - it('activates the package and does not throw an exception or log a warning', async (done) => { + it('activates the package and does not throw an exception or log a warning', async () => { spyOn(console, 'warn'); await atom.packages.activatePackage('package-with-no-activate'); expect(console.warn).not.toHaveBeenCalled(); - - done(); }); }); - it("passes the activate method the package's previously serialized state if it exists", async (done) => { + it("passes the activate method the package's previously serialized state if it exists", async () => { const pack = await atom.packages.activatePackage( 'package-with-serialization' ); @@ -1055,11 +1020,9 @@ describe('PackageManager', () => { spyOn(pack.mainModule, 'activate').and.callThrough(); await atom.packages.activatePackage('package-with-serialization'); expect(pack.mainModule.activate).toHaveBeenCalledWith({ someNumber: 77 }); - - done(); }); - it('invokes ::onDidActivatePackage listeners with the activated package', async (done) => { + it('invokes ::onDidActivatePackage listeners with the activated package', async () => { let activatedPackage; atom.packages.onDidActivatePackage(pack => { activatedPackage = pack; @@ -1067,8 +1030,6 @@ describe('PackageManager', () => { await atom.packages.activatePackage('package-with-main'); expect(activatedPackage.name).toBe('package-with-main'); - - done(); }); describe("when the package's main module throws an error on load", () => { @@ -1098,7 +1059,7 @@ describe('PackageManager', () => { }); describe('when the package is not found', () => { - it('rejects the promise', async (done) => { + it('rejects the promise', async () => { spyOn(console, 'warn'); atom.config.set('core.disabledPackages', []); @@ -1111,14 +1072,12 @@ describe('PackageManager', () => { "Failed to load package 'this-doesnt-exist'" ); } - - done(); }); }); describe('keymap loading', () => { describe("when the metadata does not contain a 'keymaps' manifest", () => { - it('loads all the .cson/.json files in the keymaps directory', async (done) => { + it('loads all the .cson/.json files in the keymaps directory', async () => { const element1 = createTestElement('test-1'); const element2 = createTestElement('test-2'); const element3 = createTestElement('test-3'); @@ -1160,13 +1119,11 @@ describe('PackageManager', () => { target: element3 }) ).toHaveLength(0); - - done(); }); }); describe("when the metadata contains a 'keymaps' manifest", () => { - it('loads only the keymaps specified by the manifest, in the specified order', async (done) => { + 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( @@ -1195,24 +1152,20 @@ describe('PackageManager', () => { target: element3 }) ).toHaveLength(0); - - done(); }); }); describe('when the keymap file is empty', () => { - it('does not throw an error on activation', async (done) => { + 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); - - done(); }); }); describe("when the package's keymaps have been disabled", () => { - it('does not add the keymaps', async (done) => { + it('does not add the keymaps', async () => { const element1 = createTestElement('test-1'); expect( atom.keymaps.findKeyBindings({ @@ -1231,8 +1184,6 @@ describe('PackageManager', () => { target: element1 }) ).toHaveLength(0); - - done(); }); }); @@ -1252,7 +1203,7 @@ describe('PackageManager', () => { }); describe("when the package's keymaps are disabled and re-enabled after it is activated", () => { - it('removes and re-adds the keymaps', async (done) => { + it('removes and re-adds the keymaps', async () => { const element1 = createTestElement('test-1'); atom.packages.observePackagesWithKeymapsDisabled(); @@ -1275,8 +1226,6 @@ describe('PackageManager', () => { target: element1 })[0].command ).toBe('keymap-1'); - - done(); }); }); @@ -1305,7 +1254,7 @@ describe('PackageManager', () => { temp.cleanupSync(); }); - it("doesn't override user-defined keymaps", async (done) => { + it("doesn't override user-defined keymaps", async () => { fs.writeFileSync( userKeymapPath, `".test-1": {"ctrl-z": "user-command"}` @@ -1326,8 +1275,6 @@ describe('PackageManager', () => { ); expect(events.length).toBe(2); expect(events[1].type).toBe('user-command'); - - done(); }); }); }); @@ -1339,7 +1286,7 @@ describe('PackageManager', () => { }); describe("when the metadata does not contain a 'menus' manifest", () => { - it('loads all the .cson/.json files in the menus directory', async (done) => { + it('loads all the .cson/.json files in the menus directory', async () => { const element = createTestElement('test-1'); expect(atom.contextMenu.templateForElement(element)).toEqual([]); @@ -1356,13 +1303,11 @@ describe('PackageManager', () => { expect(atom.contextMenu.templateForElement(element)[2].label).toBe( 'Menu item 3' ); - - done(); }); }); describe("when the metadata contains a 'menus' manifest", () => { - it('loads only the menus specified by the manifest, in the specified order', async (done) => { + it('loads only the menus specified by the manifest, in the specified order', async () => { const element = createTestElement('test-1'); expect(atom.contextMenu.templateForElement(element)).toEqual([]); @@ -1378,26 +1323,22 @@ describe('PackageManager', () => { expect( atom.contextMenu.templateForElement(element)[2] ).toBeUndefined(); - - done(); }); }); describe('when the menu file is empty', () => { - it('does not throw an error on activation', async (done) => { + 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 ); - - done(); }); }); }); 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 (done) => { + 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' ); @@ -1422,13 +1363,11 @@ describe('PackageManager', () => { getComputedStyle(document.querySelector('#jasmine-content')) .fontSize ).toBe('1px'); - - done(); }); }); describe("when the metadata does not contain a 'styleSheets' manifest", () => { - it('loads all style sheets from the styles directory', async (done) => { + it('loads all style sheets from the styles directory', async () => { const one = require.resolve( './fixtures/packages/package-with-styles/styles/1.css' ); @@ -1456,12 +1395,10 @@ describe('PackageManager', () => { getComputedStyle(document.querySelector('#jasmine-content')) .fontSize ).toBe('3px'); - - done(); }); }); - it("assigns the stylesheet's context based on the filename", async (done) => { + it("assigns the stylesheet's context based on the filename", async () => { await atom.packages.activatePackage('package-with-styles'); let count = 0; @@ -1488,47 +1425,39 @@ describe('PackageManager', () => { } expect(count).toBe(4); - - done(); }); }); describe('grammar loading', () => { - it("loads the package's grammars", async (done) => { + it("loads the package's grammars", async () => { await atom.packages.activatePackage('package-with-grammars'); expect(atom.grammars.selectGrammar('a.alot').name).toBe('Alot'); expect(atom.grammars.selectGrammar('a.alittle').name).toBe('Alittle'); - - done(); }); - it('loads any tree-sitter grammars defined in the package', async (done) => { + it('loads any tree-sitter grammars defined in the package', async () => { atom.config.set('core.useTreeSitterParsers', true); await atom.packages.activatePackage('package-with-tree-sitter-grammar'); const grammar = atom.grammars.selectGrammar('test.somelang'); expect(grammar.name).toBe('Some Language'); await grammar.getQuery('highlightsQuery'); expect(grammar.highlightsQuery.includes('(empty)')).toBe(true); - - done(); }); }); describe('scoped-property loading', () => { - it('loads the scoped properties', async (done) => { + it('loads the scoped properties', async () => { await atom.packages.activatePackage('package-with-settings'); expect( atom.config.get('editor.increaseIndentPattern', { scope: ['.source.omg'] }) ).toBe('^a'); - - done(); }); }); describe('URI handler registration', () => { - it("registers the package's specified URI handler", async (done) => { + 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'); @@ -1539,13 +1468,11 @@ describe('PackageManager', () => { atom.dispatchURIMessage(uri); await activationPromise; expect(mod.handleURI).toHaveBeenCalledWith(url.parse(uri, true), uri); - - done(); }); }); describe('service registration', () => { - it("registers the package's provided and consumed services", async (done) => { + it("registers the package's provided and consumed services", async () => { const consumerModule = require('./fixtures/packages/package-with-consumed-services'); let firstServiceV3Disposed = false; @@ -1594,11 +1521,9 @@ describe('PackageManager', () => { expect(consumerModule.consumeFirstServiceV3).not.toHaveBeenCalled(); expect(consumerModule.consumeFirstServiceV4).not.toHaveBeenCalled(); expect(consumerModule.consumeSecondService).not.toHaveBeenCalled(); - - done(); }); - it('ignores provided and consumed services that do not exist', async (done) => { + it('ignores provided and consumed services that do not exist', async () => { const addErrorHandler = jasmine.createSpy(); atom.notifications.onDidAddNotification(addErrorHandler); @@ -1619,14 +1544,12 @@ describe('PackageManager', () => { ) ).toBe(true); expect(addErrorHandler.calls.count()).toBe(0); - - done(); }); }); }); describe('::serialize', () => { - it('does not serialize packages that threw an error during activation', async (done) => { + it('does not serialize packages that threw an error during activation', async () => { spyOn(atom, 'inSpecMode').and.returnValue(false); spyOn(console, 'warn'); @@ -1637,11 +1560,9 @@ describe('PackageManager', () => { atom.packages.serialize(); expect(badPack.mainModule.serialize).not.toHaveBeenCalled(); - - done(); }); - it("absorbs exceptions that are thrown by the package module's serialize method", async (done) => { + it("absorbs exceptions that are thrown by the package module's serialize method", async () => { spyOn(console, 'error'); await atom.packages.activatePackage('package-with-serialize-error'); @@ -1654,13 +1575,11 @@ describe('PackageManager', () => { { someNumber: 1 } ); expect(console.error).toHaveBeenCalled(); - - done(); }); }); describe('::deactivatePackages()', () => { - it('deactivates all packages but does not serialize them', async (done) => { + it('deactivates all packages but does not serialize them', async () => { const pack1 = await atom.packages.activatePackage( 'package-with-deactivate' ); @@ -1673,15 +1592,13 @@ describe('PackageManager', () => { await atom.packages.deactivatePackages(); expect(pack1.mainModule.deactivate).toHaveBeenCalled(); expect(pack2.mainModule.serialize).not.toHaveBeenCalled(); - - done(); }); }); describe('::deactivatePackage(id)', () => { afterEach(() => atom.packages.unloadPackages()); - it("calls `deactivate` on the package's main module if activate was successful", async (done) => { + it("calls `deactivate` on the package's main module if activate was successful", async () => { spyOn(atom, 'inSpecMode').and.returnValue(false); const pack = await atom.packages.activatePackage( @@ -1710,33 +1627,27 @@ describe('PackageManager', () => { expect( atom.packages.isPackageActive('package-that-throws-on-activate') ).toBeFalsy(); - - done(); }); - it("absorbs exceptions that are thrown by the package module's deactivate method", async (done) => { + it("absorbs exceptions that are thrown by the package module's deactivate method", async () => { spyOn(console, 'error'); await atom.packages.activatePackage('package-that-throws-on-deactivate'); await atom.packages.deactivatePackage( 'package-that-throws-on-deactivate' ); expect(console.error).toHaveBeenCalled(); - - done(); }); - it("removes the package's grammars", async (done) => { + it("removes the package's grammars", async () => { await atom.packages.activatePackage('package-with-grammars'); await atom.packages.deactivatePackage('package-with-grammars'); expect(atom.grammars.selectGrammar('a.alot').name).toBe('Null Grammar'); expect(atom.grammars.selectGrammar('a.alittle').name).toBe( 'Null Grammar' ); - - done(); }); - it("removes the package's keymaps", async (done) => { + it("removes the package's keymaps", async () => { await atom.packages.activatePackage('package-with-keymaps'); await atom.packages.deactivatePackage('package-with-keymaps'); expect( @@ -1751,11 +1662,9 @@ describe('PackageManager', () => { target: createTestElement('test-2') }) ).toHaveLength(0); - - done(); }); - it("removes the package's stylesheets", async (done) => { + it("removes the package's stylesheets", async () => { await atom.packages.activatePackage('package-with-styles'); await atom.packages.deactivatePackage('package-with-styles'); @@ -1771,11 +1680,9 @@ describe('PackageManager', () => { expect(atom.themes.stylesheetElementForId(one)).not.toExist(); expect(atom.themes.stylesheetElementForId(two)).not.toExist(); expect(atom.themes.stylesheetElementForId(three)).not.toExist(); - - done(); }); - it("removes the package's scoped-properties", async (done) => { + it("removes the package's scoped-properties", async () => { await atom.packages.activatePackage('package-with-settings'); expect( atom.config.get('editor.increaseIndentPattern', { @@ -1789,11 +1696,9 @@ describe('PackageManager', () => { scope: ['.source.omg'] }) ).toBeUndefined(); - - done(); }); - it('invokes ::onDidDeactivatePackage listeners with the deactivated package', async (done) => { + it('invokes ::onDidDeactivatePackage listeners with the deactivated package', async () => { await atom.packages.activatePackage('package-with-main'); let deactivatedPackage; @@ -1803,8 +1708,6 @@ describe('PackageManager', () => { await atom.packages.deactivatePackage('package-with-main'); expect(deactivatedPackage.name).toBe('package-with-main'); - - done(); }); }); @@ -1819,23 +1722,19 @@ describe('PackageManager', () => { expect(loadedPackages.length).toBeGreaterThan(0); }); - afterEach(async (done) => { + afterEach(async () => { await atom.packages.deactivatePackages(); atom.packages.unloadPackages(); jasmine.restoreDeprecationsSnapshot(); - - done(); }); - it('sets hasActivatedInitialPackages', async (done) => { + it('sets hasActivatedInitialPackages', async () => { spyOn(atom.styles, 'getUserStyleSheetPath').and.returnValue(null); spyOn(atom.packages, 'activatePackages'); expect(atom.packages.hasActivatedInitialPackages()).toBe(false); await atom.packages.activate(); expect(atom.packages.hasActivatedInitialPackages()).toBe(true); - - done(); }); it('activates all the packages, and none of the themes', () => { @@ -1856,7 +1755,7 @@ describe('PackageManager', () => { themes.map(theme => expect(['theme']).toContain(theme.getType())); }); - it('calls callbacks registered with ::onDidActivateInitialPackages', async (done) => { + 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( @@ -1878,14 +1777,12 @@ describe('PackageManager', () => { expect(atom.packages.getActivePackages().includes(package1)).toBe(true); expect(atom.packages.getActivePackages().includes(package2)).toBe(true); expect(atom.packages.getActivePackages().includes(package3)).toBe(false); - - done(); }); }); describe('::enablePackage(id) and ::disablePackage(id)', () => { describe('with packages', () => { - it('enables a disabled package', async (done) => { + it('enables a disabled package', async () => { const packageName = 'package-with-main'; atom.config.pushAtKeyPath('core.disabledPackages', packageName); atom.packages.observeDisabledPackages(); @@ -1901,11 +1798,9 @@ describe('PackageManager', () => { expect(atom.config.get('core.disabledPackages')).not.toContain( packageName ); - - done(); }); - it('disables an enabled package', async (done) => { + it('disables an enabled package', async () => { const packageName = 'package-with-main'; const pack = await atom.packages.activatePackage(packageName); @@ -1920,8 +1815,6 @@ describe('PackageManager', () => { expect(atom.packages.getActivePackages()).not.toContain(pack); expect(atom.config.get('core.disabledPackages')).toContain(packageName); - - done(); }); it('returns null if the package cannot be loaded', () => { @@ -1948,7 +1841,7 @@ describe('PackageManager', () => { beforeEach(() => atom.themes.activateThemes()); afterEach(() => atom.themes.deactivateThemes()); - it('enables and disables a theme', async (done) => { + 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( @@ -1977,8 +1870,6 @@ describe('PackageManager', () => { expect(atom.config.get('core.disabledPackages')).not.toContain( packageName ); - - done(); }); }); }); diff --git a/spec/package-spec.js b/spec/package-spec.js index 0bc64a5cb6..3953e33bee 100644 --- a/spec/package-spec.js +++ b/spec/package-spec.js @@ -100,7 +100,7 @@ describe('Package', function() { afterEach(() => (atom.packages.devMode = true)); - it('returns a promise resolving to the results of `apm rebuild`', async function(done) { + it('returns a promise resolving to the results of `apm rebuild`', async function() { const packagePath = __guard__(atom.project.getDirectories()[0], x => x.resolve('packages/package-with-index') ); @@ -122,8 +122,6 @@ describe('Package', function() { stdout: 'stdout output', stderr: 'stderr output' }); - - done(); }); it('persists build failures in local storage', function() { @@ -168,12 +166,10 @@ describe('Package', function() { jasmine.attachToDOM(editorElement); }); - afterEach(async (done) => { + afterEach(async () => { if (theme != null) { await theme.deactivate(); } - - done(); }); describe('when the theme contains a single style file', function() { @@ -259,13 +255,11 @@ describe('Package', function() { theme.activate(); }); - it('deactivated event fires on .deactivate()', async function(done) { + it('deactivated event fires on .deactivate()', async function() { let spy = jasmine.createSpy(); theme.onDidDeactivate(spy); await theme.deactivate(); expect(spy).toHaveBeenCalled(); - - done(); }); }); }); diff --git a/spec/pane-container-element-spec.js b/spec/pane-container-element-spec.js index 7dae8a0ae6..d6909ff28a 100644 --- a/spec/pane-container-element-spec.js +++ b/spec/pane-container-element-spec.js @@ -152,7 +152,7 @@ describe('PaneContainerElement', function() { const getPaneElement = i => containerElement.querySelectorAll('atom-pane')[i]; - it('adds and removes panes in the direction that the pane is being dragged', async function(done) { + it('adds and removes panes in the direction that the pane is being dragged', async function() { const leftPane = container.getActivePane(); expectPaneScale([leftPane, 1]); @@ -180,11 +180,9 @@ describe('PaneContainerElement', function() { await leftPane.close(); expectPaneScale([rightPane, 1]); - - done(); }); - it('splits or closes panes in orthogonal direction that the pane is being dragged', async function(done) { + it('splits or closes panes in orthogonal direction that the pane is being dragged', async function() { const leftPane = container.getActivePane(); expectPaneScale([leftPane, 1]); @@ -209,8 +207,6 @@ describe('PaneContainerElement', function() { await lowerPane.close(); expectPaneScale([leftPane, 0.5], [rightPane, 1.5]); - - done(); }); describe('when the pane is detached', () => { diff --git a/spec/pane-container-spec.js b/spec/pane-container-spec.js index cc9e854523..25e959bf19 100644 --- a/spec/pane-container-spec.js +++ b/spec/pane-container-spec.js @@ -285,22 +285,18 @@ describe('PaneContainer', () => { pane2.addItem(new TestItem()); }); - it('returns true if the user saves all modified files when prompted', async (done) => { + it('returns true if the user saves all modified files when prompted', async () => { confirm.and.callFake((options, callback) => callback(0)); const saved = await container.confirmClose(); expect(confirm).toHaveBeenCalled(); expect(saved).toBeTruthy(); - - done(); }); - it('returns false if the user cancels saving any modified file', async (done) => { + it('returns false if the user cancels saving any modified file', async () => { confirm.and.callFake((options, callback) => callback(1)); const saved = await container.confirmClose(); expect(confirm).toHaveBeenCalled(); expect(saved).toBeFalsy(); - - done(); }); }); @@ -396,7 +392,7 @@ describe('PaneContainer', () => { }); describe('::onWillDestroyPaneItem() and ::onDidDestroyPaneItem()', () => { - it('invokes the given callbacks when an item will be destroyed on any pane', async (done) => { + it('invokes the given callbacks when an item will be destroyed on any pane', async () => { const container = new PaneContainer(params); const pane1 = container.getRoot(); const item1 = {}; @@ -444,13 +440,11 @@ describe('PaneContainer', () => { expect(events[4][1].pane).toEqual(pane2); expect(events[4][1].index).toEqual(0); expect(typeof events[4][1].prevent).toEqual('function'); - - done(); }); }); describe('::saveAll()', () => - it('saves all modified pane items', async (done) => { + it('saves all modified pane items', async () => { const container = new PaneContainer(params); const pane1 = container.getRoot(); pane1.splitRight(); @@ -501,8 +495,6 @@ describe('PaneContainer', () => { expect(item1.saved).toBe(true); expect(item2.saved).toBe(false); expect(item3.saved).toBe(true); - - done(); })); describe('::moveActiveItemToPane(destPane) and ::copyActiveItemToPane(destPane)', () => { diff --git a/spec/pane-spec.js b/spec/pane-spec.js index d8d58e4420..8cc6076a4b 100644 --- a/spec/pane-spec.js +++ b/spec/pane-spec.js @@ -392,7 +392,7 @@ describe('Pane', () => { expect(callbackCalled).toBeTruthy(); }); - it("isn't called when a pending item is replaced with a new one", async (done) => { + it("isn't called when a pending item is replaced with a new one", async () => { pane = null; const pendingSpy = jasmine.createSpy('onItemDidTerminatePendingState'); const destroySpy = jasmine.createSpy('onWillDestroyItem'); @@ -407,8 +407,6 @@ describe('Pane', () => { expect(destroySpy).toHaveBeenCalled(); expect(pendingSpy).not.toHaveBeenCalled(); - - done(); }); }); @@ -594,7 +592,7 @@ describe('Pane', () => { expect(pane.getActiveItem()).toBe(item1); }); - it('invokes ::onWillDestroyItem() and PaneContainer::onWillDestroyPaneItem observers before destroying the item', async (done) => { + it('invokes ::onWillDestroyItem() and PaneContainer::onWillDestroyPaneItem observers before destroying the item', async () => { jasmine.useRealClock(); pane.container = new PaneContainer({ config: atom.config, confirm }); const events = []; @@ -625,8 +623,6 @@ describe('Pane', () => { expect(events[1][1].index).toEqual(1); expect(typeof events[1][1].prevent).toEqual('function'); expect(events[1][1].pane).toEqual(pane); - - done(); }); it('invokes ::onWillRemoveItem() observers', () => { @@ -677,7 +673,7 @@ describe('Pane', () => { describe('if the [Save] option is selected', () => { describe('when the item has a uri', () => { - it('saves the item before destroying it', async (done) => { + it('saves the item before destroying it', async () => { itemURI = 'test'; confirm.and.callFake((options, callback) => callback(0)); @@ -686,13 +682,11 @@ describe('Pane', () => { expect(pane.getItems().includes(item1)).toBe(false); expect(item1.isDestroyed()).toBe(true); expect(success).toBe(true); - - done(); }); }); describe('when the item has no uri', () => { - it('presents a save-as dialog, then saves the item with the given uri before removing and destroying it', async (done) => { + it('presents a save-as dialog, then saves the item with the given uri before removing and destroying it', async () => { jasmine.useRealClock(); itemURI = null; @@ -710,14 +704,12 @@ describe('Pane', () => { expect(pane.getItems().includes(item1)).toBe(false); expect(item1.isDestroyed()).toBe(true); expect(success).toBe(true); - - done(); }); }); }); describe("if the [Don't Save] option is selected", () => { - it('removes and destroys the item without saving it', async (done) => { + it('removes and destroys the item without saving it', async () => { confirm.and.callFake((options, callback) => callback(2)); const success = await pane.destroyItem(item1); @@ -725,13 +717,11 @@ describe('Pane', () => { expect(pane.getItems().includes(item1)).toBe(false); expect(item1.isDestroyed()).toBe(true); expect(success).toBe(true); - - done(); }); }); describe('if the [Cancel] option is selected', () => { - it('does not save, remove, or destroy the item', async (done) => { + it('does not save, remove, or destroy the item', async () => { confirm.and.callFake((options, callback) => callback(1)); const success = await pane.destroyItem(item1); @@ -739,20 +729,16 @@ describe('Pane', () => { expect(pane.getItems().includes(item1)).toBe(true); expect(item1.isDestroyed()).toBe(false); expect(success).toBe(false); - - done(); }); }); describe('when force=true', () => { - it('destroys the item immediately', async (done) => { + it('destroys the item immediately', async () => { const success = await pane.destroyItem(item1, true); expect(item1.save).not.toHaveBeenCalled(); expect(pane.getItems().includes(item1)).toBe(false); expect(item1.isDestroyed()).toBe(true); expect(success).toBe(true); - - done(); }); }); }); @@ -783,24 +769,20 @@ describe('Pane', () => { }); describe('when passed a permanent dock item', () => { - it("doesn't destroy the item", async (done) => { + it("doesn't destroy the item", async () => { spyOn(item1, 'isPermanentDockItem').and.returnValue(true); const success = await pane.destroyItem(item1); expect(pane.getItems().includes(item1)).toBe(true); expect(item1.isDestroyed()).toBe(false); expect(success).toBe(false); - - done(); }); - it('destroy the item if force=true', async (done) => { + it('destroy the item if force=true', async () => { spyOn(item1, 'isPermanentDockItem').and.returnValue(true); const success = await pane.destroyItem(item1, true); expect(pane.getItems().includes(item1)).toBe(false); expect(item1.isDestroyed()).toBe(true); expect(success).toBe(true); - - done(); }); }); }); @@ -823,7 +805,7 @@ describe('Pane', () => { }); describe('::destroyItems()', () => { - it('destroys all items', async (done) => { + it('destroys all items', async () => { const pane = new Pane( paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) ); @@ -834,8 +816,6 @@ describe('Pane', () => { expect(item2.isDestroyed()).toBe(true); expect(item3.isDestroyed()).toBe(true); expect(pane.getItems()).toEqual([]); - - done(); }); }); @@ -910,35 +890,29 @@ describe('Pane', () => { describe('when the current item has no uri', () => { describe('when the current item has a saveAs method', () => { - it('opens a save dialog and saves the current item as the selected path', async (done) => { + it('opens a save dialog and saves the current item as the selected path', async () => { pane.getActiveItem().saveAs = jasmine.createSpy('saveAs'); await pane.saveActiveItem(); expect(showSaveDialog.calls.mostRecent().args[0]).toEqual({}); expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith( '/selected/path' ); - - done(); }); }); describe('when the current item has no saveAs method', () => { - it('does nothing', async (done) => { + it('does nothing', async () => { expect(pane.getActiveItem().saveAs).toBeUndefined(); await pane.saveActiveItem(); expect(showSaveDialog).not.toHaveBeenCalled(); - - done(); }); }); - it('does nothing if the user cancels choosing a path', async (done) => { + it('does nothing if the user cancels choosing a path', async () => { pane.getActiveItem().saveAs = jasmine.createSpy('saveAs'); showSaveDialog.and.callFake((options, callback) => callback(undefined)); await pane.saveActiveItem(); expect(pane.getActiveItem().saveAs).not.toHaveBeenCalled(); - - done(); }); }); @@ -994,7 +968,7 @@ describe('Pane', () => { }); describe('when the current item has a saveAs method', () => { - it('opens the save dialog and calls saveAs on the item with the selected path', async (done) => { + it('opens the save dialog and calls saveAs on the item with the selected path', async () => { jasmine.useRealClock(); pane.getActiveItem().path = __filename; @@ -1010,8 +984,6 @@ describe('Pane', () => { expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith( '/selected/path' ); - - done(); }); }); @@ -1387,7 +1359,7 @@ describe('Pane', () => { }); describe('::close()', () => { - it('prompts to save unsaved items before destroying the pane', async (done) => { + it('prompts to save unsaved items before destroying the pane', async () => { const pane = new Pane( paneParams({ items: [new Item('A'), new Item('B')] }) ); @@ -1402,11 +1374,9 @@ describe('Pane', () => { expect(confirm).toHaveBeenCalled(); expect(item1.save).toHaveBeenCalled(); expect(pane.isDestroyed()).toBe(true); - - done(); }); - it('does not destroy the pane if the user clicks cancel', async (done) => { + it('does not destroy the pane if the user clicks cancel', async () => { const pane = new Pane( paneParams({ items: [new Item('A'), new Item('B')] }) ); @@ -1422,11 +1392,9 @@ describe('Pane', () => { expect(confirm).toHaveBeenCalled(); expect(item1.save).not.toHaveBeenCalled(); expect(pane.isDestroyed()).toBe(false); - - done(); }); - it('does not destroy the pane if the user starts to save but then does not choose a path', async (done) => { + 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')] }) ); @@ -1443,8 +1411,6 @@ describe('Pane', () => { expect(confirm.calls.count()).toBe(1); expect(item1.saveAs).not.toHaveBeenCalled(); expect(pane.isDestroyed()).toBe(false); - - done(); }); describe('when item fails to save', () => { @@ -1469,7 +1435,7 @@ describe('Pane', () => { }); }); - it('does not destroy the pane if save fails and user clicks cancel', async (done) => { + it('does not destroy the pane if save fails and user clicks cancel', async () => { let confirmations = 0; confirm.and.callFake((options, callback) => { confirmations++; @@ -1485,11 +1451,9 @@ describe('Pane', () => { expect(confirmations).toBe(2); expect(item1.save).toHaveBeenCalled(); expect(pane.isDestroyed()).toBe(false); - - done(); }); - it('does destroy the pane if the user saves the file under a new name', async (done) => { + it('does destroy the pane if the user saves the file under a new name', async () => { item1.saveAs = jasmine.createSpy('saveAs').and.returnValue(true); let confirmations = 0; @@ -1509,11 +1473,9 @@ describe('Pane', () => { expect(item1.save).toHaveBeenCalled(); expect(item1.saveAs).toHaveBeenCalled(); expect(pane.isDestroyed()).toBe(true); - - done(); }); - it('asks again if the saveAs also fails', async (done) => { + it('asks again if the saveAs also fails', async () => { item1.saveAs = jasmine.createSpy('saveAs').and.callFake(() => { const error = new Error("EACCES, permission denied '/test/path'"); error.path = '/test/path'; @@ -1542,8 +1504,6 @@ describe('Pane', () => { expect(item1.save).toHaveBeenCalled(); expect(item1.saveAs).toHaveBeenCalled(); expect(pane.isDestroyed()).toBe(true); - - done(); }); }); }); @@ -1609,20 +1569,16 @@ describe('Pane', () => { describe('pending state', () => { let editor1, pane, eventCount; - beforeEach(async (done) => { + beforeEach(async () => { editor1 = await atom.workspace.open('sample.txt', { pending: true }); pane = atom.workspace.getActivePane(); eventCount = 0; editor1.onDidTerminatePendingState(() => eventCount++); - - done(); }); - it('does not open file in pending state by default', async (done) => { + it('does not open file in pending state by default', async () => { await atom.workspace.open('sample.js'); expect(pane.getPendingItem()).toBeNull(); - - done(); }); it("opens file in pending state if 'pending' option is true", () => { @@ -1644,7 +1600,7 @@ describe('Pane', () => { expect(eventCount).toBe(1); }); - it('only calls terminate handler once when text is modified twice', async (done) => { + it('only calls terminate handler once when text is modified twice', async () => { const originalText = editor1.getText(); editor1.insertText('Some text'); advanceClock(editor1.getBuffer().stoppedChangingDelay); @@ -1660,8 +1616,6 @@ describe('Pane', () => { // Reset fixture back to original state editor1.setText(originalText); await editor1.save(); - - done(); }); it('only calls clearPendingItem if there is a pending item to clear', () => { diff --git a/spec/panel-container-element-spec.js b/spec/panel-container-element-spec.js index ce1757d9a3..d4975d0ca7 100644 --- a/spec/panel-container-element-spec.js +++ b/spec/panel-container-element-spec.js @@ -255,7 +255,7 @@ describe('PanelContainerElement', () => { panel.destroy() }); - it('returns focus to the original activeElement', async (done) => { + it('returns focus to the original activeElement', async () => { const panel = createPanel(); const previousActiveElement = document.activeElement; const panelEl = panel.getElement(); @@ -268,8 +268,6 @@ describe('PanelContainerElement', () => { await conditionPromise(() => document.activeElement === previousActiveElement); expect(document.activeElement).toBe(previousActiveElement); - - done(); }); }); }); diff --git a/spec/path-watcher-spec.js b/spec/path-watcher-spec.js index d8892e5043..a2a9a4e6d9 100644 --- a/spec/path-watcher-spec.js +++ b/spec/path-watcher-spec.js @@ -24,11 +24,9 @@ describe('watchPath', function() { subs = new CompositeDisposable(); }); - afterEach(async function(done) { + afterEach(async function() { subs.dispose(); await stopAllWatchers(); - - done(); }); function waitForChanges(watcher, ...fileNames) { @@ -54,27 +52,23 @@ describe('watchPath', function() { } describe('watchPath()', function() { - it('resolves the returned promise when the watcher begins listening', async function(done) { + it('resolves the returned promise when the watcher begins listening', async function() { const rootDir = await tempMkdir('atom-fsmanager-test-'); const watcher = await watchPath(rootDir, {}, () => {}); expect(watcher.constructor.name).toBe('PathWatcher'); - - done(); }); - it('reuses an existing native watcher and resolves getStartPromise immediately if attached to a running watcher', async function(done) { + it('reuses an existing native watcher and resolves getStartPromise immediately if attached to a running watcher', async function() { const rootDir = await tempMkdir('atom-fsmanager-test-'); const watcher0 = await watchPath(rootDir, {}, () => {}); const watcher1 = await watchPath(rootDir, {}, () => {}); expect(watcher0.native).toBe(watcher1.native); - - done(); }); - it("reuses existing native watchers even while they're still starting", async function(done) { + it("reuses existing native watchers even while they're still starting", async function() { const rootDir = await tempMkdir('atom-fsmanager-test-'); const [watcher0, watcher1] = await Promise.all([ @@ -82,11 +76,9 @@ describe('watchPath', function() { watchPath(rootDir, {}, () => {}) ]); expect(watcher0.native).toBe(watcher1.native); - - done(); }); - it("doesn't attach new watchers to a native watcher that's stopping", async function(done) { + it("doesn't attach new watchers to a native watcher that's stopping", async function() { const rootDir = await tempMkdir('atom-fsmanager-test-'); const watcher0 = await watchPath(rootDir, {}, () => {}); @@ -96,11 +88,9 @@ describe('watchPath', function() { const watcher1 = await watchPath(rootDir, {}, () => {}); expect(watcher1.native).not.toBe(native0); - - done(); }); - it('reuses an existing native watcher on a parent directory and filters events', async function(done) { + it('reuses an existing native watcher on a parent directory and filters events', async function() { const rootDir = await tempMkdir('atom-fsmanager-test-').then(realpath); const rootFile = path.join(rootDir, 'rootfile.txt'); const subDir = path.join(rootDir, 'subdir'); @@ -125,11 +115,9 @@ describe('watchPath', function() { const nextRootEvent = waitForChanges(rootWatcher, rootFile); await writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' }); await nextRootEvent; - - done(); }); - it('adopts existing child watchers and filters events appropriately to them', async function(done) { + it('adopts existing child watchers and filters events appropriately to them', async function() { const parentDir = await tempMkdir('atom-fsmanager-test-').then(realpath); // Create the directory tree @@ -180,8 +168,6 @@ describe('watchPath', function() { subWatcherChanges1, parentWatcherChanges ]); - - done(); }); }); }); diff --git a/spec/project-spec.js b/spec/project-spec.js index 0c8b67a5a6..3b8777b43b 100644 --- a/spec/project-spec.js +++ b/spec/project-spec.js @@ -31,7 +31,7 @@ describe('Project', () => { } }); - it("does not deserialize paths to directories that don't exist", async (done) => { + it("does not deserialize paths to directories that don't exist", async () => { deserializedProject = new Project({ notificationManager: atom.notifications, packageManager: atom.packages, @@ -48,11 +48,9 @@ describe('Project', () => { expect(err.missingProjectPaths).toEqual([ '/directory/that/does/not/exist' ]); - - done(); }); - it('does not deserialize paths that are now files', async (done) => { + it('does not deserialize paths that are now files', async () => { const childPath = path.join(temp.mkdirSync('atom-spec-project'), 'child'); fs.mkdirSync(childPath); @@ -73,11 +71,9 @@ describe('Project', () => { expect(deserializedProject.getPaths()).toEqual([]); expect(err.missingProjectPaths).toEqual([childPath]); - - done(); }); - it('does not include unretained buffers in the serialized state', async (done) => { + it('does not include unretained buffers in the serialized state', async () => { await atom.project.bufferForPath('a'); expect(atom.project.getBuffers().length).toBe(1); @@ -92,11 +88,9 @@ describe('Project', () => { await deserializedProject.deserialize(atom.project.serialize({ isUnloading: false })); expect(deserializedProject.getBuffers().length).toBe(0); - - done(); }); - it('listens for destroyed events on deserialized buffers and removes them when they are destroyed', async (done) => { + it('listens for destroyed events on deserialized buffers and removes them when they are destroyed', async () => { await atom.workspace.open('a'); expect(atom.project.getBuffers().length).toBe(1); @@ -112,11 +106,9 @@ describe('Project', () => { expect(deserializedProject.getBuffers().length).toBe(1); deserializedProject.getBuffers()[0].destroy(); expect(deserializedProject.getBuffers().length).toBe(0); - - done(); }); - it('does not deserialize buffers when their path is now a directory', async (done) => { + it('does not deserialize buffers when their path is now a directory', async () => { const pathToOpen = path.join( temp.mkdirSync('atom-spec-project'), 'file.txt' @@ -136,8 +128,6 @@ describe('Project', () => { await deserializedProject.deserialize(atom.project.serialize({ isUnloading: false })); expect(deserializedProject.getBuffers().length).toBe(0); - - done(); }); it('does not deserialize buffers when their path is inaccessible', async (done) => { @@ -167,7 +157,7 @@ describe('Project', () => { done(); }); - it('does not deserialize buffers with their path is no longer present', async (done) => { + it('does not deserialize buffers with their path is no longer present', async () => { const pathToOpen = path.join( temp.mkdirSync('atom-spec-project'), 'file.txt' @@ -188,11 +178,9 @@ describe('Project', () => { await deserializedProject.deserialize(atom.project.serialize({ isUnloading: false })); expect(deserializedProject.getBuffers().length).toBe(0); - - done(); }); - it('deserializes buffers that have never been saved before', async (done) => { + it('deserializes buffers that have never been saved before', async () => { const pathToOpen = path.join( temp.mkdirSync('atom-spec-project'), 'file.txt' @@ -215,11 +203,9 @@ describe('Project', () => { expect(deserializedProject.getBuffers().length).toBe(1); expect(deserializedProject.getBuffers()[0].getPath()).toBe(pathToOpen); expect(deserializedProject.getBuffers()[0].getText()).toBe('unsaved\n'); - - done(); }); - it('serializes marker layers and history only if Atom is quitting', async (done) => { + it('serializes marker layers and history only if Atom is quitting', async () => { await atom.workspace.open('a'); let bufferA = atom.project.getBuffers()[0]; @@ -254,13 +240,11 @@ describe('Project', () => { x.getMarker(markerA.id) ).not.toBeUndefined(); expect(quittingProject.getBuffers()[0].undo()).toBe(true); - - done(); }); }); describe('when an editor is saved and the project has no path', () => { - it("sets the project's path to the saved file's parent directory", async (done) => { + it("sets the project's path to the saved file's parent directory", async () => { const tempFile = temp.openSync().path; atom.project.setPaths([]); expect(atom.project.getPaths()[0]).toBeUndefined(); @@ -269,8 +253,6 @@ describe('Project', () => { await editor.saveAs(tempFile); expect(atom.project.getPaths()[0]).toBe(path.dirname(tempFile)) - - done(); }); }); @@ -321,16 +303,14 @@ describe('Project', () => { describe('before and after saving a buffer', () => { let buffer; - beforeEach(async (done) => { + beforeEach(async () => { buffer = await atom.project.bufferForPath(path.join(__dirname, 'fixtures', 'sample.js')) buffer.retain(); - - done(); }); afterEach(() => buffer.release()); - it('emits save events on the main process', async (done) => { + it('emits save events on the main process', async () => { spyOn(atom.project.applicationDelegate, 'emitDidSavePath'); spyOn(atom.project.applicationDelegate, 'emitWillSavePath'); @@ -348,17 +328,13 @@ describe('Project', () => { expect( atom.project.applicationDelegate.emitWillSavePath ).toHaveBeenCalledWith(buffer.getPath()); - - done(); }); }); describe('when a watch error is thrown from the TextBuffer', () => { let editor = null; - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open(require.resolve('./fixtures/dir/a')); - - done(); }); it('creates a warning notification', () => { @@ -533,7 +509,7 @@ describe('Project', () => { expect(atom.project.getDirectories().length).toBe(0); }); - it('uses the custom onDidChangeFiles as the watcher if available', async (done) => { + it('uses the custom onDidChangeFiles as the watcher if available', async () => { // Ensure that all preexisting watchers are stopped await stopAllWatchers(); @@ -551,8 +527,6 @@ describe('Project', () => { expect(changeSpy).toHaveBeenCalledWith(events); disposable.dispose(); - - done(); }); }); @@ -566,29 +540,25 @@ 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'", async (done) => { + it("returns a new edit session for the given path and emits 'buffer-created'", async () => { let editor = await atom.workspace.open(absolutePath); expect(editor.buffer.getPath()).toBe(absolutePath); expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer); - - done(); }); }); 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'", async (done) => { + it("returns a new edit session for the given path (relative to the project root) and emits 'buffer-created'", async () => { let editor = await atom.workspace.open(absolutePath); expect(editor.buffer.getPath()).toBe(absolutePath); expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer); - - done(); }); }); describe('when passed the path to a buffer that is currently opened', () => { - it('returns a new edit session containing currently opened buffer', async (done) => { + it('returns a new edit session containing currently opened buffer', async () => { let editor = await atom.workspace.open(absolutePath); let buffer; @@ -601,19 +571,15 @@ describe('Project', () => { buffer = (await atom.workspace.open('a')).buffer; expect(buffer).toBe(editor.buffer); expect(newBufferHandler).not.toHaveBeenCalled(); - - done(); }); }); describe('when not passed a path', () => { - it("returns a new edit session and emits 'buffer-created'", async (done) => { + it("returns a new edit session and emits 'buffer-created'", async () => { let editor = await atom.workspace.open(); expect(editor.buffer.getPath()).toBeUndefined(); expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer); - - done(); }); }); }); @@ -621,17 +587,15 @@ describe('Project', () => { describe('.bufferForPath(path)', () => { let buffer = null; - beforeEach(async (done) => { + beforeEach(async () => { buffer = await atom.project.bufferForPath('a'); buffer.retain(); - - done(); }); afterEach(() => buffer.release()); describe('when opening a previously opened path', () => { - it('does not create a new buffer', async (done) => { + it('does not create a new buffer', async () => { expect(await atom.project.bufferForPath('a')).toBe(buffer) expect(await atom.project.bufferForPath('b')).not.toBe(buffer) @@ -641,11 +605,9 @@ describe('Project', () => { ]); expect(buffer1).toBe(buffer2); - - done(); }); - it('retries loading the buffer if it previously failed', async (done) => { + it('retries loading the buffer if it previously failed', async () => { const error = new Error('Could not open file'); spyOn(TextBuffer, 'load').and.callFake(() => Promise.reject(error) @@ -653,31 +615,27 @@ describe('Project', () => { await atom.project.bufferForPath('b').catch(e => expect(e).toBe(error)) TextBuffer.load.and.callThrough(); - await atom.project.bufferForPath('b').then(() => done()) + await atom.project.bufferForPath('b') }); - it('creates a new buffer if the previous buffer was destroyed', async (done) => { + it('creates a new buffer if the previous buffer was destroyed', async () => { buffer.release(); expect(await atom.project.bufferForPath('b')).not.toBe(buffer); - - done(); }); }); }); describe('.repositoryForDirectory(directory)', () => { - it('resolves to null when the directory does not have a repository', async (done) => { + it('resolves to null when the directory does not have a repository', async () => { const directory = new Directory('/tmp'); const result = await atom.project.repositoryForDirectory(directory); expect(result).toBeNull(); expect(atom.project.repositoryProviders.length).toBeGreaterThan(0); expect(atom.project.repositoryPromisesByPath.size).toBe(0); - - done(); }); - it('resolves to a GitRepository and is cached when the given directory is a Git repo', async (done) => { + it('resolves to a GitRepository and is cached when the given directory is a Git repo', async () => { const directory = new Directory(path.join(__dirname, '..')); const promise = atom.project.repositoryForDirectory(directory); @@ -689,11 +647,9 @@ describe('Project', () => { // Verify that the result is cached. expect(atom.project.repositoryForDirectory(directory)).toBe(promise); - - done(); }); - it('creates a new repository if a previous one with the same directory had been destroyed', async (done) => { + it('creates a new repository if a previous one with the same directory had been destroyed', async () => { let repository = null; const directory = new Directory(path.join(__dirname, '..')); @@ -706,8 +662,6 @@ describe('Project', () => { repository = await atom.project.repositoryForDirectory(directory); expect(repository.isDestroyed()).toBe(false); - - done(); }); }); @@ -987,7 +941,7 @@ describe('Project', () => { }); describe('.onDidAddBuffer()', () => { - it('invokes the callback with added text buffers', async (done) => { + it('invokes the callback with added text buffers', async () => { const buffers = []; const added = []; @@ -1000,13 +954,11 @@ describe('Project', () => { expect(buffers.length).toBe(2); expect(added).toEqual([buffers[1]]); - - done(); }); }); describe('.observeBuffers()', () => { - it('invokes the observer with current and future text buffers', async (done) => { + it('invokes the observer with current and future text buffers', async () => { const buffers = []; const observed = []; @@ -1022,8 +974,6 @@ describe('Project', () => { expect(observed.length).toBe(3); expect(buffers.length).toBe(3); expect(observed).toEqual(buffers); - - done(); }); }); @@ -1218,10 +1168,12 @@ describe('Project', () => { }); describe('.resolvePath(uri)', () => { - it('normalizes disk drive letter in passed path on win32', () => { - jasmine.filterByPlatform({only: ['win32']}); + it('normalizes disk drive letter in passed path on win32', (done) => { + jasmine.filterByPlatform({only: ['win32']}, done); expect(atom.project.resolvePath('d:\\file.txt')).toEqual('D:\\file.txt'); + + done(); }); }); }); diff --git a/spec/reopen-project-menu-manager-spec.js b/spec/reopen-project-menu-manager-spec.js index a38778121f..e3f2038078 100644 --- a/spec/reopen-project-menu-manager-spec.js +++ b/spec/reopen-project-menu-manager-spec.js @@ -277,20 +277,24 @@ describe('ReopenProjectMenuManager', () => { expect(name).toBe('three'); }); - it('returns the standard base name for a relative Windows path', () => { - jasmine.filterByPlatform({only: ['win32']}); + it('returns the standard base name for a relative Windows path', (done) => { + jasmine.filterByPlatform({only: ['win32']}, done); const name = ReopenProjectMenuManager.betterBaseName('.\\one\\two'); expect(name).toBe('two'); + + done(); }); - it('returns the standard base name for an absolute Windows path', () => { - jasmine.filterByPlatform({only: ['win32']}); + it('returns the standard base name for an absolute Windows path', (done) => { + jasmine.filterByPlatform({only: ['win32']}, done); const name = ReopenProjectMenuManager.betterBaseName( 'c:\\missions\\apollo\\11' ); expect(name).toBe('11'); + + done(); }); it('returns the drive root for a Windows drive name', () => { diff --git a/spec/runners/jasmine2-test-runner.js b/spec/runners/jasmine2-test-runner.js index 6e28749fde..13195716d0 100644 --- a/spec/runners/jasmine2-test-runner.js +++ b/spec/runners/jasmine2-test-runner.js @@ -18,6 +18,7 @@ temp.track(); module.exports = function({logFile, headless, testPaths, buildAtomEnvironment}) { // Load Jasmine 2.x require('../helpers/jasmine2-singleton'); + defineJasmineHelpersOnWindow(jasmine.getEnv()) // Build Atom Environment const { atomHome, applicationDelegate } = require('../helpers/build-atom-environment'); @@ -59,9 +60,7 @@ module.exports = function({logFile, headless, testPaths, buildAtomEnvironment}) jasmine.currentEnv_ = null; // As all the jasmine helpers (it, describe, etc..) were registered to the previous environment, we need to re-set them on window - for (let key in jasmine.getEnv()) { - window[key] = jasmine.getEnv()[key]; - } + defineJasmineHelpersOnWindow(jasmine.getEnv()); // Set up a specFilter to disable all passing spec and re-run only the flaky ones jasmine.getEnv().specFilter = (spec) => { @@ -85,6 +84,38 @@ module.exports = function({logFile, headless, testPaths, buildAtomEnvironment}) }) }; +const defineJasmineHelpersOnWindow = (jasmineEnv) => { + for (let key in jasmineEnv) { + window[key] = jasmineEnv[key]; + } + + ['it', 'fit', 'xit'].forEach((key) => { + window[key] = (name, originalFn) => { + jasmineEnv[key](name, async (done) => { + if(originalFn.length === 0) { + await originalFn() + done(); + } else { + originalFn(done); + } + }); + } + }); + + ['beforeEach', 'afterEach'].forEach((key) => { + window[key] = (originalFn) => { + jasmineEnv[key](async (done) => { + if(originalFn.length === 0) { + await originalFn() + done(); + } else { + originalFn(done); + } + }) + } + }); +} + const loadSpecsAndRunThem = (logFile, headless, testPaths) => { return new Promise((resolve) => { const jasmineEnv = jasmine.getEnv(); diff --git a/spec/scope-resolver-spec.js b/spec/scope-resolver-spec.js index a0032eaf5c..278cd60afa 100644 --- a/spec/scope-resolver-spec.js +++ b/spec/scope-resolver-spec.js @@ -95,21 +95,19 @@ function rangeFromDescriptor(rawRange) { describe('ScopeResolver', () => { let editor, buffer, grammar; - beforeEach(async (done) => { + beforeEach(async () => { grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); editor = await atom.workspace.open(''); buffer = editor.getBuffer(); atom.grammars.addGrammar(grammar); atom.config.set('core.useTreeSitterParsers', true); - - done(); }); afterEach(() => { ScopeResolver.clearConfigCache(); }); - it('resolves all scopes in absence of any tests or adjustments', async (done) => { + it('resolves all scopes in absence of any tests or adjustments', async () => { await grammar.setQueryForTest('highlightsQuery', ` (comment) @comment (string) @string @@ -132,11 +130,9 @@ describe('ScopeResolver', () => { expect(stringForNodeRange(range)) .toBe(stringForNodeRange(node)); } - - done(); }); - it('provides the grammar with the text of leaf nodes only', async (done) => { + it('provides the grammar with the text of leaf nodes only', async () => { await grammar.setQueryForTest('highlightsQuery', ` (expression_statement) @not_leaf_node (call_expression) @also_not_leaf_node @@ -166,11 +162,9 @@ describe('ScopeResolver', () => { 'cc', 'dd', ]); - - done(); }); - it('interpolates magic tokens in scope names', async (done) => { + it('interpolates magic tokens in scope names', async () => { await grammar.setQueryForTest('highlightsQuery', ` (lexical_declaration kind: _ @declaration._TYPE_) `); @@ -195,11 +189,9 @@ describe('ScopeResolver', () => { 'declaration.const', 'declaration.let' ]); - - done(); }); - it('does not apply any scopes when @_IGNORE_ is used', async (done) => { + it('does not apply any scopes when @_IGNORE_ is used', async () => { await grammar.setQueryForTest('highlightsQuery', ` (lexical_declaration kind: _ @_IGNORE_ (#match? @_IGNORE_ "const")) @@ -227,11 +219,9 @@ describe('ScopeResolver', () => { expect(!!result).toBe(true); } } - - done(); }); - it('does not apply any scopes when multiple @_IGNORE_s are used', async (done) => { + it('does not apply any scopes when multiple @_IGNORE_s are used', async () => { await grammar.setQueryForTest('highlightsQuery', ` (variable_declarator (identifier) @_IGNORE_.identifier @@ -259,13 +249,11 @@ describe('ScopeResolver', () => { expect(!!result).toBe(true); } } - - done(); }); describe('adjustments', () => { - it('adjusts ranges with (#set! adjust.startAt)', async (done) => { + it('adjusts ranges with (#set! adjust.startAt)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((try_statement) @try.plus.brace (#set! adjust.endAt @@ -286,11 +274,9 @@ describe('ScopeResolver', () => { expect(buffer.getTextInRange(rangeFromDescriptor(range))) .toBe('try {'); - - done(); }); - it('adjusts ranges with (#set! adjust.endAt)', async (done) => { + it('adjusts ranges with (#set! adjust.endAt)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((object) @object.interior (#set! adjust.startAt firstChild.endPosition) @@ -313,11 +299,9 @@ describe('ScopeResolver', () => { expect( buffer.getTextInRange(rangeFromDescriptor(range)) ).toBe(`from: 'x', to: 'y'`); - - done(); }); - it('adjusts ranges with (#set! adjust.offset(Start|End))', async (done) => { + it('adjusts ranges with (#set! adjust.offset(Start|End))', async () => { // Same result as the previous test, but with a different technique. await grammar.setQueryForTest('highlightsQuery', ` ((object) @object.interior @@ -340,11 +324,9 @@ describe('ScopeResolver', () => { expect( buffer.getTextInRange(rangeFromDescriptor(range)) ).toBe(`from: 'x', to: 'y'`); - - done(); }); - it('prevents adjustments outside the original capture', async (done) => { + it('prevents adjustments outside the original capture', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((comment) @too-early (#set! adjust.startAt previousSibling.startPosition)) @@ -375,11 +357,9 @@ describe('ScopeResolver', () => { scopeResolver.store(capture); }).toThrow(); } - - done(); }); - it("adjusts a range around a regex match with `adjust.startAndEndAroundFirstMatchOf`", async (done) => { + it("adjusts a range around a regex match with `adjust.startAndEndAroundFirstMatchOf`", async () => { await grammar.setQueryForTest('highlightsQuery', ` ((comment) @todo (#set! adjust.startAndEndAroundFirstMatchOf "\\\\sTODO(?=:)")) @@ -409,14 +389,12 @@ describe('ScopeResolver', () => { expect( buffer.getTextInRange(rangeFromDescriptor(matched[0])) ).toBe(` TODO`); - - done(); }); }); describe('tests', () => { - it('rejects scopes for ranges that have already been claimed by another capture with (#set! capture.final)', async (done) => { + it('rejects scopes for ranges that have already been claimed by another capture with (#set! capture.final)', async () => { await grammar.setQueryForTest('highlightsQuery', ` (comment) @comment (string) @string0 @@ -450,11 +428,9 @@ describe('ScopeResolver', () => { expect(!!result).toBe(false); } } - - done(); }); - it('temporarily supports the deprecated (#set! test.final true)', async (done) => { + it('temporarily supports the deprecated (#set! test.final true)', async () => { await grammar.setQueryForTest('highlightsQuery', ` (comment) @comment (string) @string0 @@ -488,11 +464,9 @@ describe('ScopeResolver', () => { expect(!!result).toBe(false); } } - - done(); }); - it('rejects scopes for ranges that have already been claimed by another capture with (#set! capture.final)', async (done) => { + it('rejects scopes for ranges that have already been claimed by another capture with (#set! capture.final)', async () => { await grammar.setQueryForTest('highlightsQuery', ` (comment) @comment (string) @string0 @@ -526,11 +500,9 @@ describe('ScopeResolver', () => { expect(!!result).toBe(false); } } - - done(); }); - it('rejects scopes for ranges that have already been claimed if set with (#set! capture.shy true)', async (done) => { + it('rejects scopes for ranges that have already been claimed if set with (#set! capture.shy true)', async () => { await grammar.setQueryForTest('highlightsQuery', ` (comment) @comment (string "\\"") @string.double @@ -560,11 +532,9 @@ describe('ScopeResolver', () => { expect(!!result).toBe(expected); } } - - done(); }); - it('temporarily supports the deprecated (#set! test.shy true)', async (done) => { + it('temporarily supports the deprecated (#set! test.shy true)', async () => { await grammar.setQueryForTest('highlightsQuery', ` (comment) @comment (string "\\"") @string.double @@ -594,11 +564,9 @@ describe('ScopeResolver', () => { expect(!!result).toBe(expected); } } - - done(); }); - it('rejects scopes for ranges that fail test.first or test.last', async (done) => { + it('rejects scopes for ranges that fail test.first or test.last', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((string_fragment) @impossible.first (#is? test.first true)) @@ -635,11 +603,9 @@ describe('ScopeResolver', () => { expect(node.id).toBe(node.parent.firstChild.id); } } - - done(); }); - it('temporarily supports the deprecated (#set! test.onlyIfFirst) and (#set! test.onlyIfLast)', async (done) => { + it('temporarily supports the deprecated (#set! test.onlyIfFirst) and (#set! test.onlyIfLast)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((string_fragment) @impossible.first (#is? test.onlyIfFirst true)) @@ -676,11 +642,9 @@ describe('ScopeResolver', () => { expect(node.id).toBe(node.parent.firstChild.id); } } - - done(); }); - it('supports test.firstOfType and test.lastOfType', async (done) => { + it('supports test.firstOfType and test.lastOfType', async () => { await grammar.setQueryForTest('highlightsQuery', ` (formal_parameters (identifier) @first-param (#is? test.firstOfType identifier)) @@ -713,11 +677,9 @@ describe('ScopeResolver', () => { expect(matched.map(pair => { return pair[0].name; })).toEqual(["first-param", "first-comma", "last-comma", "last-param"]); - - done(); }); - it('supports test.lastTextOnRow', async (done) => { + it('supports test.lastTextOnRow', async () => { await grammar.setQueryForTest('highlightsQuery', ` ("||" @hanging-logical-operator (#is? test.lastTextOnRow true)) @@ -746,11 +708,9 @@ describe('ScopeResolver', () => { expect(matched.map(capture => capture.name)).toEqual( ["hanging-logical-operator"]); - - done(); }); - it('supports test.firstTextOnRow', async (done) => { + it('supports test.firstTextOnRow', async () => { await grammar.setQueryForTest('highlightsQuery', ` ("||" @hanging-logical-operator (#is? test.firstTextOnRow true)) @@ -779,11 +739,9 @@ describe('ScopeResolver', () => { expect(matched.map(capture => capture.name)).toEqual( ["hanging-logical-operator"]); - - done(); }); - it('supports test.descendantOfType', async (done) => { + it('supports test.descendantOfType', async () => { await grammar.setQueryForTest('highlightsQuery', ` ("," @comma-inside-function (#is? test.descendantOfType function_declaration)) @@ -803,11 +761,9 @@ describe('ScopeResolver', () => { expect(matched.every(cap => { return cap.node.startPosition.row === 1; })).toBe(true); - - done(); }); - it('supports test.descendantOfType (multiple values)', async (done) => { + it('supports test.descendantOfType (multiple values)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ("," @comma-inside-function (#is? test.descendantOfType "function_declaration generator_function_declaration")) @@ -829,12 +785,10 @@ describe('ScopeResolver', () => { let expectedRow = index >= 2 ? 2 : 1; return cap.node.startPosition.row === expectedRow; })).toBe(true); - - done(); }); - it('supports test.ancestorOfType', async (done) => { + it('supports test.ancestorOfType', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((function_declaration) @function-with-semicolons (#is? test.ancestorOfType ";")) @@ -854,11 +808,9 @@ describe('ScopeResolver', () => { expect(matched.length).toBe(1); expect(matched[0].node.text.includes("function bar")).toBe(true); - - done(); }); - it('supports test.ancestorOfType (multiple values)', async (done) => { + it('supports test.ancestorOfType (multiple values)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((function_declaration) @function-with-semicolons-or-booleans (#is? test.ancestorOfType "; false")) @@ -882,11 +834,9 @@ describe('ScopeResolver', () => { expect(matched.length).toBe(2); expect(matched[0].node.text.includes("function ba")).toBe(true); expect(matched[1].node.text.includes("function ba")).toBe(true); - - done(); }); - it('supports test.descendantOfNodeWithData (without value)', async (done) => { + it('supports test.descendantOfNodeWithData (without value)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((function_declaration) @_IGNORE_ (#match? @_IGNORE_ "foo") @@ -911,11 +861,9 @@ describe('ScopeResolver', () => { return cap.node.startPosition.row === 0 && cap.node.text === ","; })).toBe(true); - - done(); }); - it('supports test.descendantOfNodeWithData (with right value)', async (done) => { + it('supports test.descendantOfNodeWithData (with right value)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((function_declaration) @_IGNORE_ (#match? @_IGNORE_ "foo" ) @@ -940,11 +888,9 @@ describe('ScopeResolver', () => { return cap.node.startPosition.row === 0 && cap.node.text === ","; })).toBe(true); - - done(); }); - it('supports test.descendantOfNodeWithData (with wrong value)', async (done) => { + it('supports test.descendantOfNodeWithData (with wrong value)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((function_declaration) @_IGNORE_ (#match? @_IGNORE_ "foo") @@ -966,11 +912,9 @@ describe('ScopeResolver', () => { // Wrong value, so test shouldn't pass. expect(matched.length).toBe(0); - - done(); }); - it('supports test.type', async (done) => { + it('supports test.type', async () => { await grammar.setQueryForTest('highlightsQuery', ` (formal_parameters _ @function-comma (#is? test.type ",")) @@ -989,11 +933,9 @@ describe('ScopeResolver', () => { expect(matched.every(cap => { return cap.node.text === ","; })).toBe(true); - - done(); }); - it('supports test.type with multiple types', async (done) => { + it('supports test.type with multiple types', async () => { await grammar.setQueryForTest('highlightsQuery', ` (formal_parameters _ @thing (#is? test.type ", identifier")) @@ -1009,11 +951,9 @@ describe('ScopeResolver', () => { let matched = await getAllMatches(grammar, languageMode); expect(matched.length).toBe(5); - - done(); }); - it('supports test.hasError', async (done) => { + it('supports test.hasError', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((statement_block) @messed-up-statement-block (#is? test.hasError true)) @@ -1034,11 +974,9 @@ describe('ScopeResolver', () => { expect(matched.every(cap => { return cap.name === 'messed-up-statement-block' && cap.node.hasError(); })).toBe(true); - - done(); }); - it('supports test.root', async (done) => { + it('supports test.root', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((_) @is-root (#is? test.root true)) @@ -1060,11 +998,9 @@ describe('ScopeResolver', () => { return cap.name === 'is-root' && cap.node.type === 'program' && !cap.node.parent; })).toBe(true); - - done(); }); - it('supports test.lastTextOnRow', async (done) => { + it('supports test.lastTextOnRow', async () => { await grammar.setQueryForTest('highlightsQuery', ` ("||" @orphaned-operator (#is? test.lastTextOnRow true)) @@ -1088,11 +1024,9 @@ describe('ScopeResolver', () => { expect(cap.node.type).toBe('||'); expect(cap.node.startPosition.row).toBe(2); } - - done(); }); - it('supports test.rangeWithData (without value)', async (done) => { + it('supports test.rangeWithData (without value)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((true) @_IGNORE_ (#set! isTrue true)) ([ (true) (false) ] @optimistic-boolean @@ -1116,11 +1050,9 @@ describe('ScopeResolver', () => { expect(cap.name).toBe('optimistic-boolean'); expect(cap.node.text).toBe('true'); } - - done(); }); - it('supports test.rangeWithData (with right value)', async (done) => { + it('supports test.rangeWithData (with right value)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((true) @_IGNORE_ (#set! isTrue "exactly")) ([ (true) (false) ] @optimistic-boolean @@ -1144,11 +1076,9 @@ describe('ScopeResolver', () => { expect(cap.name).toBe('optimistic-boolean'); expect(cap.node.text).toBe('true'); } - - done(); }); - it('supports test.rangeWithData (with wrong value)', async (done) => { + it('supports test.rangeWithData (with wrong value)', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((true) @_IGNORE_ (#set! isTrue "perhaps")) ([ (true) (false) ] @optimistic-boolean @@ -1169,11 +1099,9 @@ describe('ScopeResolver', () => { // Values don't match, so the test shouldn't pass. expect(matched.length).toBe(0); - - done(); }); - it('supports test.startsOnSameRowAs', async (done) => { + it('supports test.startsOnSameRowAs', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((false) @non-hanging-false (#is? test.startsOnSameRowAs parent.startPosition)) @@ -1198,11 +1126,9 @@ describe('ScopeResolver', () => { expect(cap.node.text).toBe('false'); expect(cap.node.startPosition.row).toBe(1); } - - done(); }); - it('supports test.endsOnSameRowAs', async (done) => { + it('supports test.endsOnSameRowAs', async () => { await grammar.setQueryForTest('highlightsQuery', ` ((true) @non-hanging-true (#is? test.endsOnSameRowAs parent.endPosition)) @@ -1227,11 +1153,9 @@ describe('ScopeResolver', () => { expect(cap.node.text).toBe('true'); expect(cap.node.startPosition.row).toBe(1); } - - done(); }); - it('supports test.config (with no arguments)', async (done) => { + it('supports test.config (with no arguments)', async () => { atom.config.set('core.careAboutBooleans', true); await grammar.setQueryForTest('highlightsQuery', ` @@ -1256,11 +1180,9 @@ describe('ScopeResolver', () => { matched = await getAllMatches(grammar, languageMode); expect(matched.length).toBe(0); - - done(); }); - it('supports test.config (with boolean arguments)', async (done) => { + it('supports test.config (with boolean arguments)', async () => { atom.config.set('core.careAboutBooleans', true); await grammar.setQueryForTest('highlightsQuery', ` @@ -1285,11 +1207,9 @@ describe('ScopeResolver', () => { matched = await getAllMatches(grammar, languageMode); expect(matched.length).toBe(0); - - done(); }); - it('supports test.config (with number arguments)', async (done) => { + it('supports test.config (with number arguments)', async () => { atom.config.set('core.careAboutBooleans', 0); await grammar.setQueryForTest('highlightsQuery', ` @@ -1314,11 +1234,9 @@ describe('ScopeResolver', () => { matched = await getAllMatches(grammar, languageMode); expect(matched.length).toBe(0); - - done(); }); - it('supports test.config (with string arguments)', async (done) => { + it('supports test.config (with string arguments)', async () => { atom.config.set('core.careAboutBooleans', "something"); await grammar.setQueryForTest('highlightsQuery', ` @@ -1364,11 +1282,9 @@ describe('ScopeResolver', () => { ); matched = await getAllMatchesWithScopeResolver(grammar, languageMode, scopeResolver); expect(matched.length).toBe(0); - - done(); }); - it('supports test.injection', async (done) => { + it('supports test.injection', async () => { jasmine.useRealClock(); await grammar.setQueryForTest('highlightsQuery', ` ((escape_sequence) @regex-escape @@ -1417,8 +1333,6 @@ describe('ScopeResolver', () => { for (let cap of matched) { expect(cap.node.startPosition.row).toBe(3); } - - done(); }); }); diff --git a/spec/state-store-spec.js b/spec/state-store-spec.js index 10b15b0486..693670d6a8 100644 --- a/spec/state-store-spec.js +++ b/spec/state-store-spec.js @@ -46,7 +46,7 @@ describe('StateStore', () => { }); describe('when there is an error reading from the database', () => { - it('rejects the promise returned by load', async (done) => { + it('rejects the promise returned by load', async () => { const store = new StateStore(databaseName, version); const fakeErrorEvent = { @@ -74,8 +74,6 @@ describe('StateStore', () => { .catch(event => { expect(event).toBe(fakeErrorEvent); }); - - done(); }); }); }); diff --git a/spec/task-spec.js b/spec/task-spec.js index 63fcad0c57..8395aca468 100644 --- a/spec/task-spec.js +++ b/spec/task-spec.js @@ -3,7 +3,7 @@ const Grim = require('grim'); describe('Task', function() { describe('@once(taskPath, args..., callback)', () => - it('terminates the process after it completes', async function(done) { + it('terminates the process after it completes', async function() { let handlerResult = null; let task; let processErroredCallbak = jasmine.createSpy(); @@ -26,11 +26,9 @@ describe('Task', function() { expect(handlerResult).toBe('hello'); expect(childProcess.kill).toHaveBeenCalled(); expect(processErroredCallbak).not.toHaveBeenCalled(); - - done(); })); - it('calls listeners registered with ::on when events are emitted in the task', async function(done) { + it('calls listeners registered with ::on when events are emitted in the task', async function() { const task = new Task(require.resolve('./fixtures/task-spec-handler')); const eventSpy = jasmine.createSpy('eventSpy'); @@ -39,11 +37,9 @@ describe('Task', function() { await new Promise((resolve) => task.start(resolve)) expect(eventSpy).toHaveBeenCalledWith(1, 2, 3); - - done(); }); - it('unregisters listeners when the Disposable returned by ::on is disposed', async function(done) { + it('unregisters listeners when the Disposable returned by ::on is disposed', async function() { const task = new Task(require.resolve('./fixtures/task-spec-handler')); const eventSpy = jasmine.createSpy('eventSpy'); @@ -53,11 +49,9 @@ describe('Task', function() { await new Promise((resolve) => task.start(resolve)) expect(eventSpy).not.toHaveBeenCalled(); - - done(); }); - it('reports deprecations in tasks', async function(done) { + it('reports deprecations in tasks', async function() { jasmine.snapshotDeprecations(); const handlerPath = require.resolve( './fixtures/task-handler-with-deprecations' @@ -69,8 +63,6 @@ describe('Task', function() { expect(deprecations.length).toBe(1); expect(deprecations[0].getStacks()[0][1].fileName).toBe(handlerPath); jasmine.restoreDeprecationsSnapshot(); - - done(); }); it('adds data listeners to standard out and error to report output', function() { @@ -114,7 +106,7 @@ describe('Task', function() { expect(completedEventSpy).not.toHaveBeenCalled(); }); - it("does not dispatch 'task:cancelled' when invoked on an inactive task", async function(done) { + it("does not dispatch 'task:cancelled' when invoked on an inactive task", async function() { let task = null; await new Promise(resolve => { @@ -128,8 +120,6 @@ describe('Task', function() { task.on('task:cancelled', cancelledEventSpy); expect(task.cancel()).toBe(false); expect(cancelledEventSpy).not.toHaveBeenCalled(); - - done(); }); }); }); diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index e6b920593a..41191b88c8 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -66,7 +66,7 @@ describe('TextEditorComponent', () => { }); describe('rendering', () => { - it('renders lines and line numbers for the visible region', async (done) => { + it('renders lines and line numbers for the visible region', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 3, autoHeight: false @@ -133,11 +133,9 @@ describe('TextEditorComponent', () => { editor.lineTextForScreenRow(7), editor.lineTextForScreenRow(8) ]); - - done(); }); - it('bases the width of the lines div on the width of the longest initially-visible screen line', async (done) => { + 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, @@ -190,11 +188,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); } - - done(); }); - it('re-renders lines when their height changes', async (done) => { + it('re-renders lines when their height changes', async () => { const { component, element } = buildComponent({ rowsPerTile: 3, autoHeight: false @@ -233,11 +229,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); expect(queryOnScreenLineNumberElements(element).length).toBe(9); expect(queryOnScreenLineElements(element).length).toBe(9); - - done(); }); - it('makes the content at least as tall as the scroll container client height', async (done) => { + it('makes the content at least as tall as the scroll container client height', async () => { const { component, editor } = buildComponent({ text: 'a'.repeat(100), width: 50, @@ -254,11 +248,9 @@ describe('TextEditorComponent', () => { component.getContentHeight(), 2 ); - - done(); }); - it('honors the scrollPastEnd option by adding empty space equivalent to the clientHeight to the end of the content area', async (done) => { + it('honors the scrollPastEnd option by adding empty space equivalent to the clientHeight to the end of the content area', async () => { const { component, editor } = buildComponent({ autoHeight: false, autoWidth: false @@ -286,11 +278,9 @@ describe('TextEditorComponent', () => { expect(component.getFirstVisibleRow()).toBe( editor.getScreenLineCount() + 1 ); - - done(); }); - it('does not fire onDidChangeScrollTop listeners when assigning the same maximal value and the content height has fractional pixels (regression)', async (done) => { + 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 @@ -311,11 +301,9 @@ describe('TextEditorComponent', () => { throw new Error('Scroll top should not have changed'); }); component.setScrollTop(component.getScrollTop()); - - done(); }); - it('gives the line number tiles an explicit width and height so their layout can be strictly contained', async (done) => { + it('gives the line number tiles an explicit width and height so their layout can be strictly contained', async () => { const { component, editor } = buildComponent({ rowsPerTile: 3 }); const lineNumberGutterElement = @@ -350,11 +338,9 @@ describe('TextEditorComponent', () => { } } } - - done(); }); - it('keeps the number of tiles stable when the visible line count changes during vertical scrolling', async (done) => { + it('keeps the number of tiles stable when the visible line count changes during vertical scrolling', async () => { const { component } = buildComponent({ rowsPerTile: 3, autoHeight: false @@ -367,11 +353,9 @@ describe('TextEditorComponent', () => { await setScrollTop(component, 1 * component.getLineHeight()); expect(component.refs.lineTiles.children.length).toBe(3 + 2); // account for cursors and highlights containers - - done(); }); - it('recycles tiles on resize', async (done) => { + it('recycles tiles on resize', async () => { const { component } = buildComponent({ rowsPerTile: 2, autoHeight: false @@ -381,11 +365,9 @@ describe('TextEditorComponent', () => { const lineNode = lineNodeForScreenRow(component, 7); await setEditorHeightInLines(component, 4); expect(lineNodeForScreenRow(component, 7)).toBe(lineNode); - - done(); }); - it("updates lines numbers when a row's foldability changes (regression)", async (done) => { + it("updates lines numbers when a row's foldability changes (regression)", async () => { const { component, editor } = buildComponent({ text: 'abc\n' }); editor.setCursorBufferPosition([1, 0]); await component.getNextUpdatePromise(); @@ -404,11 +386,9 @@ describe('TextEditorComponent', () => { expect( lineNumberNodeForScreenRow(component, 0).querySelector('.foldable') ).toBeNull(); - - done(); }); - it('shows the foldable icon on the last screen row of a buffer row that can be folded', async (done) => { + it('shows the foldable icon on the last screen row of a buffer row that can be folded', async () => { const { component } = buildComponent({ text: 'abc\n de\nfghijklm\n no', softWrapped: true @@ -429,11 +409,9 @@ describe('TextEditorComponent', () => { expect( lineNumberNodeForScreenRow(component, 4).classList.contains('foldable') ).toBe(false); - - done(); }); - it('renders dummy vertical and horizontal scrollbars when content overflows', async (done) => { + it('renders dummy vertical and horizontal scrollbars when content overflows', async () => { const { component, editor } = buildComponent({ height: 100, width: 100 @@ -489,12 +467,10 @@ describe('TextEditorComponent', () => { expect(getHorizontalScrollbarHeight(component)).toBe(0); expect(verticalScrollbar.style.visibility).toBe('hidden'); expect(horizontalScrollbar.style.visibility).toBe('hidden'); - - done(); }); 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 (done) => { + it('updates the bottom/right of dummy scrollbars and client height/width measurements', async () => { const { component, element, editor } = buildComponent({ height: 100, width: 100 @@ -556,12 +532,10 @@ describe('TextEditorComponent', () => { TextEditor.didUpdateScrollbarStyles(); component.scheduleUpdate(); await component.getNextUpdatePromise(); - - done(); }); }); - it('renders cursors within the visible row range', async (done) => { + it('renders cursors within the visible row range', async () => { const { component, element, editor } = buildComponent({ height: 40, rowsPerTile: 2 @@ -604,11 +578,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); cursorNodes = Array.from(element.querySelectorAll('.cursor')); expect(cursorNodes.length).toBe(0); - - done(); }); - it('hides cursors with non-empty selections when showCursorOnSelection is false', async (done) => { + 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]]]); await component.getNextUpdatePromise(); @@ -633,8 +605,6 @@ describe('TextEditorComponent', () => { const cursorNodes = Array.from(element.querySelectorAll('.cursor')); expect(cursorNodes.length).toBe(0); } - - done(); }); /** @@ -642,7 +612,7 @@ describe('TextEditorComponent', () => { * Error: Timed out waiting on anonymous condition at * conditionPromise (/home/runner/work/pulsar/pulsar/spec/async-spec-helpers.js:20:13) */ - xit('blinks cursors when the editor is focused and the cursors are not moving', async (done) => { + xit('blinks cursors when the editor is focused and the cursors are not moving', async () => { assertDocumentFocused(); const { component, element, editor } = buildComponent(); component.props.cursorBlinkPeriod = 30; @@ -674,11 +644,9 @@ describe('TextEditorComponent', () => { expect(getComputedStyle(cursor1).opacity).toBe('1'); expect(getComputedStyle(cursor2).opacity).toBe('1'); - - done(); }); - it('gives cursors at the end of lines the width of an "x" character', async (done) => { + it('gives cursors at the end of lines the width of an "x" character', async () => { const { component, element, editor } = buildComponent(); editor.setText('abcde'); await setEditorWidthInCharacters(component, 5.5); @@ -698,11 +666,9 @@ describe('TextEditorComponent', () => { expect(element.querySelector('.cursor').offsetWidth).toBeLessThan( Math.round(component.getBaseCharacterWidth()) ); - - done(); }); - it('positions and sizes cursors correctly when they are located next to a fold marker', async (done) => { + it('positions and sizes cursors correctly when they are located next to a fold marker', async () => { const { component, element, editor } = buildComponent(); editor.foldBufferRange([[0, 3], [0, 6]]); @@ -713,11 +679,9 @@ describe('TextEditorComponent', () => { editor.setCursorScreenPosition([0, 4]); await component.getNextUpdatePromise(); verifyCursorPosition(component, element.querySelector('.cursor'), 0, 4); - - done(); }); - it('positions cursors and placeholder text correctly when the lines container has a margin and/or is padded', async (done) => { + 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' }); @@ -752,11 +716,9 @@ describe('TextEditorComponent', () => { .getBoundingClientRect().left; const linesLeft = component.refs.lineTiles.getBoundingClientRect().left; expect(placeholderTextLeft).toBe(linesLeft); - - done(); }); - it('places the hidden input element at the location of the last cursor if it is visible', async (done) => { + it('places the hidden input element at the location of the last cursor if it is visible', async () => { const { component, editor } = buildComponent({ height: 60, width: 120, @@ -783,11 +745,9 @@ describe('TextEditorComponent', () => { expect(Math.round(hiddenInput.getBoundingClientRect().left)).toBeNear( clientLeftForCharacter(component, 7, 4) ); - - done(); }); - it('soft wraps lines based on the content width when soft wrap is enabled', async (done) => { + it('soft wraps lines based on the content width when soft wrap is enabled', async () => { let baseCharacterWidth, gutterContainerWidth; { const { component, editor } = buildComponent(); @@ -813,11 +773,9 @@ describe('TextEditorComponent', () => { const { scrollContainer } = component.refs; expect(scrollContainer.clientWidth).toBe(scrollContainer.scrollWidth); - - done(); }); - it('correctly forces the display layer to index visible rows when resizing (regression)', async (done) => { + 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, @@ -831,22 +789,18 @@ describe('TextEditorComponent', () => { element.style.width = 200 + 'px'; await component.getNextUpdatePromise(); expect(queryOnScreenLineElements(element).length).toBe(24); - - done(); }); - it('decorates the line numbers of folded lines', async (done) => { + it('decorates the line numbers of folded lines', async () => { const { component, editor } = buildComponent(); editor.foldBufferRow(1); await component.getNextUpdatePromise(); expect( lineNumberNodeForScreenRow(component, 1).classList.contains('folded') ).toBe(true); - - done(); }); - it('makes lines at least as wide as the scrollContainer', async (done) => { + it('makes lines at least as wide as the scrollContainer', async () => { const { component, element, editor } = buildComponent(); const { scrollContainer } = component.refs; editor.setText('a'); @@ -855,11 +809,9 @@ describe('TextEditorComponent', () => { expect(element.querySelector('.line').offsetWidth).toBe( scrollContainer.offsetWidth - verticalScrollbarWidth ); - - done(); }); - it('resizes based on the content when the autoHeight and/or autoWidth options are true', async (done) => { + 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 @@ -901,8 +853,6 @@ describe('TextEditorComponent', () => { 2 * editorPadding ); expect(element.offsetHeight).toBeGreaterThan(initialHeight); - - done(); }); it('does not render the line number gutter at all if the isLineNumberGutterVisible parameter is false', () => { @@ -912,7 +862,7 @@ describe('TextEditorComponent', () => { 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 (done) => { + 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).toBeNear( @@ -960,8 +910,6 @@ describe('TextEditorComponent', () => { ) ).toBe(true); checkScrollContainerLeft(component); - - done(); }); it('supports the placeholderText parameter', () => { @@ -970,7 +918,7 @@ describe('TextEditorComponent', () => { expect(element.textContent).toContain(placeholderText); }); - it('adds the data-grammar attribute and updates it when the grammar changes', async (done) => { + 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(); @@ -979,22 +927,18 @@ describe('TextEditorComponent', () => { atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.js'); await component.getNextUpdatePromise(); expect(element.dataset.grammar).toBe('source js'); - - done(); }); - it('adds the data-encoding attribute and updates it when the encoding changes', async (done) => { + it('adds the data-encoding attribute and updates it when the encoding changes', async () => { const { editor, element, component } = buildComponent(); expect(element.dataset.encoding).toBe('utf8'); editor.setEncoding('ascii'); await component.getNextUpdatePromise(); expect(element.dataset.encoding).toBe('ascii'); - - done(); }); - it('adds the has-selection class when the editor has a non-empty selection', async (done) => { + it('adds the has-selection class when the editor has a non-empty selection', async () => { const { editor, element, component } = buildComponent(); expect(element.classList.contains('has-selection')).toBe(false); @@ -1005,11 +949,9 @@ describe('TextEditorComponent', () => { editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[1, 0], [1, 0]]]); await component.getNextUpdatePromise(); expect(element.classList.contains('has-selection')).toBe(false); - - done(); }); - it('assigns buffer-row and screen-row to each line number as data fields', async (done) => { + it('assigns buffer-row and screen-row to each line number as data fields', async () => { const { editor, element, component } = buildComponent(); editor.setSoftWrapped(true); await component.getNextUpdatePromise(); @@ -1123,11 +1065,9 @@ describe('TextEditorComponent', () => { '20' ]); } - - done(); }); - it('does not blow away class names added to the element by packages when changing the class name', async (done) => { + it('does not blow away class names added to the element by packages when changing the class name', async () => { assertDocumentFocused(); const { component, element } = buildComponent(); element.classList.add('a', 'b'); @@ -1138,11 +1078,9 @@ describe('TextEditorComponent', () => { document.body.focus(); await component.getNextUpdatePromise(); expect(element.className).toBe('editor a b'); - - done(); }); - it('does not blow away class names managed by the component when packages change the element class name', async (done) => { + it('does not blow away class names managed by the component when packages change the element class name', async () => { assertDocumentFocused(); const { component, element } = buildComponent({ mini: true }); element.classList.add('a', 'b'); @@ -1152,11 +1090,9 @@ describe('TextEditorComponent', () => { element.className = 'a c d'; await component.getNextUpdatePromise(); expect(element.className).toBe('a c d editor is-focused mini'); - - done(); }); - it('ignores resize events when the editor is hidden', async (done) => { + it('ignores resize events when the editor is hidden', async () => { const { component, element } = buildComponent({ autoHeight: false }); @@ -1198,8 +1134,6 @@ describe('TextEditorComponent', () => { expect(component.getLineNumberGutterWidth()).toBe( originalLineNumberGutterWidth ); - - done(); }); describe('randomized tests', () => { @@ -1214,7 +1148,7 @@ describe('TextEditorComponent', () => { jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; }); - it('renders the visible rows correctly after randomly mutating the editor', async (done) => { + it('renders the visible rows correctly after randomly mutating the editor', async () => { const initialSeed = Date.now(); for (var i = 0; i < 20; i++) { let seed = initialSeed + i; @@ -1325,8 +1259,6 @@ describe('TextEditorComponent', () => { element.remove(); editor.destroy(); } - - done(); }); }); }); @@ -1355,7 +1287,7 @@ describe('TextEditorComponent', () => { expect(element.querySelector('gutter-container')).toBeNull(); }); - it('does not render line decorations for the cursor line', async (done) => { + 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') @@ -1372,11 +1304,9 @@ describe('TextEditorComponent', () => { expect( element.querySelector('.line').classList.contains('cursor-line') ).toBe(false); - - done(); }); - it('does not render scrollbars', async (done) => { + it('does not render scrollbars', async () => { const { component, editor } = buildComponent({ mini: true, autoHeight: false @@ -1390,8 +1320,6 @@ describe('TextEditorComponent', () => { expect(component.canScrollHorizontally()).toBe(false); expect(component.refs.horizontalScrollbar).toBeUndefined(); expect(component.refs.verticalScrollbar).toBeUndefined(); - - done(); }); }); @@ -1400,7 +1328,7 @@ describe('TextEditorComponent', () => { assertDocumentFocused(); }); - it('focuses the hidden input element and adds the is-focused class when focused', async (done) => { + it('focuses the hidden input element and adds the is-focused class when focused', async () => { const { component, element } = buildComponent(); const { hiddenInput } = component.refs.cursorsAndInput.refs; @@ -1418,11 +1346,9 @@ describe('TextEditorComponent', () => { expect(document.activeElement).not.toBe(hiddenInput); await component.getNextUpdatePromise(); expect(element.classList.contains('is-focused')).toBe(false); - - done(); }); - it('updates the component when the hidden input is focused directly', async (done) => { + it('updates the component when the hidden input is focused directly', async () => { const { component, element } = buildComponent(); const { hiddenInput } = component.refs.cursorsAndInput.refs; expect(element.classList.contains('is-focused')).toBe(false); @@ -1431,8 +1357,6 @@ describe('TextEditorComponent', () => { hiddenInput.focus(); await component.getNextUpdatePromise(); expect(element.classList.contains('is-focused')).toBe(true); - - done(); }); it('gracefully handles a focus event that occurs prior to the attachedCallback of the element', () => { @@ -1448,7 +1372,7 @@ describe('TextEditorComponent', () => { ); }); - it('gracefully handles a focus event that occurs prior to detecting the element has become visible', async (done) => { + it('gracefully handles a focus event that occurs prior to detecting the element has become visible', async () => { const { component, element } = buildComponent({ attach: false }); element.style.display = 'none'; jasmine.attachToDOM(element); @@ -1459,8 +1383,6 @@ describe('TextEditorComponent', () => { expect(document.activeElement).toBe( component.refs.cursorsAndInput.refs.hiddenInput ); - - done(); }); it('emits blur events only when focus shifts to something other than the editor itself or its hidden input', () => { @@ -1479,7 +1401,7 @@ describe('TextEditorComponent', () => { }); describe('autoscroll', () => { - it('automatically scrolls vertically when the requested range is within the vertical scroll margin of the top or bottom', async (done) => { + 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 }); @@ -1507,11 +1429,9 @@ describe('TextEditorComponent', () => { editor.scrollToScreenPosition([2, 0]); await component.getNextUpdatePromise(); expect(component.getScrollTop()).toBe(0); - - done(); }); - it('does not vertically autoscroll by more than half of the visible lines if the editor is shorter than twice the scroll margin', async (done) => { + 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 }); @@ -1546,11 +1466,9 @@ describe('TextEditorComponent', () => { expect(component.getScrollBottom()).toBeNear( (6 + 1 + scrollMarginInLines) * component.measurements.lineHeight ); - - done(); }); - it('autoscrolls the given range to the center of the screen if the `center` option is true', async (done) => { + it('autoscrolls the given range to the center of the screen if the `center` option is true', async () => { const { component, editor } = buildComponent({ height: 50 }); expect(component.getLastVisibleRow()).toBe(2); @@ -1561,11 +1479,9 @@ describe('TextEditorComponent', () => { (component.getScrollTop() + component.getScrollBottom()) / 2; const expectedScrollCenter = ((4 + 7) / 2) * component.getLineHeight(); expect(actualScrollCenter).toBeCloseTo(expectedScrollCenter, 0); - - done(); }); - 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 (done) => { + 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(); element.style.width = component.getGutterContainerWidth() + @@ -1594,11 +1510,9 @@ describe('TextEditorComponent', () => { component.measurements.baseCharacterWidth - component.getScrollContainerClientWidth(); expect(component.getScrollLeft()).toBeNear(expectedScrollLeft); - - done(); }); - 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 (done) => { + 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, @@ -1618,11 +1532,9 @@ describe('TextEditorComponent', () => { component.getBaseCharacterWidth() ); expect(component.getScrollLeft()).toBeNear(expectedScrollLeft); - - done(); }); - it('correctly autoscrolls after inserting a line that exceeds the current content width', async (done) => { + it('correctly autoscrolls after inserting a line that exceeds the current content width', async () => { const { component, element, editor } = buildComponent(); element.style.width = component.getGutterContainerWidth() + @@ -1637,11 +1549,9 @@ describe('TextEditorComponent', () => { expect(component.getScrollLeft()).toBeNear( component.getScrollWidth() - component.getScrollContainerClientWidth() ); - - done(); }); - it('does not try to measure lines that do not exist when the animation frame is delivered', async (done) => { + 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, @@ -1653,11 +1563,9 @@ describe('TextEditorComponent', () => { expect(component.getScrollBottom()).toBeNear( (10 + 1) * component.measurements.lineHeight ); - - done(); }); - it('accounts for the presence of horizontal scrollbars that appear during the same frame as the autoscroll', async (done) => { + 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 }); @@ -1682,8 +1590,6 @@ describe('TextEditorComponent', () => { spyOn(window, 'onerror'); await setScrollTop(component, 0); expect(window.onerror).not.toHaveBeenCalled(); - - done(); }); }); @@ -1855,7 +1761,7 @@ describe('TextEditorComponent', () => { } }); - it('inverts deltaX and deltaY when holding shift on Windows and Linux', async (done) => { + it('inverts deltaX and deltaY when holding shift on Windows and Linux', async () => { const scrollSensitivity = 50; const { component } = buildComponent({ height: 50, @@ -1999,13 +1905,11 @@ describe('TextEditorComponent', () => { ); await setScrollLeft(component, 0); } - - done(); }); }); describe('scrolling via the API', () => { - it('ignores scroll requests to NaN, null or undefined positions', async (done) => { + it('ignores scroll requests to NaN, null or undefined positions', async () => { const { component } = buildComponent({ rowsPerTile: 2, autoHeight: false @@ -2038,13 +1942,11 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); expect(component.getScrollTop()).toBeNear(initialScrollTop); expect(component.getScrollLeft()).toBeNear(initialScrollLeft); - - done(); }); }); describe('line and line number decorations', () => { - it('adds decoration classes on screen lines spanned by decorated markers', async (done) => { + it('adds decoration classes on screen lines spanned by decorated markers', async () => { const { component, editor } = buildComponent({ softWrapped: true }); @@ -2189,11 +2091,9 @@ describe('TextEditorComponent', () => { expect( lineNumberNodeForScreenRow(component, 8).classList.contains('b') ).toBe(true); - - done(); }); - it('honors the onlyEmpty and onlyNonEmpty decoration options', async (done) => { + it('honors the onlyEmpty and onlyNonEmpty decoration options', async () => { const { component, editor } = buildComponent(); const marker = editor.markScreenPosition([1, 0]); editor.decorateMarker(marker, { @@ -2264,11 +2164,9 @@ describe('TextEditorComponent', () => { expect( lineNumberNodeForScreenRow(component, 2).classList.contains('c') ).toBe(true); - - done(); }); - it('honors the onlyHead option', async (done) => { + it('honors the onlyHead option', async () => { const { component, editor } = buildComponent(); const marker = editor.markScreenRange([[1, 4], [3, 4]]); editor.decorateMarker(marker, { @@ -2290,11 +2188,9 @@ describe('TextEditorComponent', () => { expect( lineNumberNodeForScreenRow(component, 3).classList.contains('a') ).toBe(true); - - done(); }); - it('only decorates the last row of non-empty ranges that end at column 0 if omitEmptyLastRow is false', async (done) => { + it('only decorates the last row of non-empty ranges that end at column 0 if omitEmptyLastRow is false', async () => { const { component, editor } = buildComponent(); const marker = editor.markScreenRange([[1, 0], [3, 0]]); editor.decorateMarker(marker, { @@ -2327,11 +2223,9 @@ describe('TextEditorComponent', () => { expect(lineNodeForScreenRow(component, 3).classList.contains('b')).toBe( true ); - - done(); }); - it('does not decorate invalidated markers', async (done) => { + it('does not decorate invalidated markers', async () => { const { component, editor } = buildComponent(); const marker = editor.markScreenRange([[1, 0], [3, 0]], { invalidate: 'touch' @@ -2351,13 +2245,11 @@ describe('TextEditorComponent', () => { expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( false ); - - done(); }); }); describe('highlight decorations', () => { - it('renders single-line highlights', async (done) => { + it('renders single-line highlights', async () => { const { component, element, editor } = buildComponent(); const marker = editor.markScreenRange([[1, 2], [1, 10]]); editor.decorateMarker(marker, { type: 'highlight', class: 'a' }); @@ -2398,11 +2290,9 @@ describe('TextEditorComponent', () => { clientLeftForCharacter(component, 1, 8) ); } - - done(); }); - it('renders multi-line highlights', async (done) => { + it('renders multi-line highlights', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 3 }); const marker = editor.markScreenRange([[2, 4], [3, 4]]); editor.decorateMarker(marker, { type: 'highlight', class: 'a' }); @@ -2494,11 +2384,9 @@ describe('TextEditorComponent', () => { clientLeftForCharacter(component, 5, 4) ); } - - done(); }); - it('can flash highlight decorations', async (done) => { + it('can flash highlight decorations', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 3, height: 200 @@ -2536,11 +2424,9 @@ describe('TextEditorComponent', () => { await conditionPromise(() => highlights[0].classList.contains('e')); await conditionPromise(() => !highlights[0].classList.contains('e')); - - done(); }); - it("flashing a highlight decoration doesn't unflash other highlight decorations", async (done) => { + it("flashing a highlight decoration doesn't unflash other highlight decorations", async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 3, height: 200 @@ -2563,11 +2449,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); expect(highlights[0].classList.contains('c')).toBe(true); expect(highlights[0].classList.contains('d')).toBe(true); - - done(); }); - it('supports layer decorations', async (done) => { + it('supports layer decorations', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 12 }); @@ -2600,11 +2484,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); expect(highlights[0].classList.contains('a')).toBe(true); expect(highlights[1].classList.contains('c')).toBe(true); - - done(); }); - it('clears highlights when recycling a tile that previously contained highlights and now does not', async (done) => { + 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 @@ -2618,11 +2500,9 @@ describe('TextEditorComponent', () => { await setScrollTop(component, component.getLineHeight() * 3); expect(element.querySelectorAll('.highlight.a').length).toBe(0); - - done(); }); - it('does not move existing highlights when adding or removing other highlight decorations (regression)', async (done) => { + it('does not move existing highlights when adding or removing other highlight decorations (regression)', async () => { const { component, element, editor } = buildComponent(); const marker1 = editor.markScreenRange([[1, 6], [1, 10]]); @@ -2649,11 +2529,9 @@ describe('TextEditorComponent', () => { expect( Array.from(marker1Region.parentElement.children).indexOf(marker1Region) ).toBe(0); - - done(); }); - it('correctly positions highlights that end on rows preceding or following block decorations', async (done) => { + it('correctly positions highlights that end on rows preceding or following block decorations', async () => { const { editor, element, component } = buildComponent(); const item1 = document.createElement('div'); @@ -2682,8 +2560,6 @@ describe('TextEditorComponent', () => { expect(regions[0].offsetTop).toBeNear(3 * component.getLineHeight()); expect(regions[0].offsetHeight).toBeNear(component.getLineHeight()); expect(regions[1].offsetTop).toBeNear(4 * component.getLineHeight() + 30); - - done(); }); }); @@ -2704,7 +2580,7 @@ describe('TextEditorComponent', () => { return fakeWindow; } - it('renders overlay elements at the specified screen position unless it would overflow the window', async (done) => { + it('renders overlay elements at the specified screen position unless it would overflow the window', async () => { const { component, editor } = buildComponent({ width: 200, height: 100, @@ -2804,11 +2680,9 @@ describe('TextEditorComponent', () => { decoration.setProperties({ type: 'overlay', item: overlayElement }); await component.getNextUpdatePromise(); expect(overlayWrapper.classList.contains('b')).toBe(false); - - done(); }); - it('does not attempt to avoid overflowing the window if `avoidOverflow` is false on the decoration', async (done) => { + it('does not attempt to avoid overflowing the window if `avoidOverflow` is false on the decoration', async () => { const { component, editor } = buildComponent({ width: 200, height: 100, @@ -2836,13 +2710,11 @@ describe('TextEditorComponent', () => { expect(overlayElement.getBoundingClientRect().left).toBeLessThan( fakeWindow.getBoundingClientRect().left ); - - done(); }); }); describe('custom gutter decorations', () => { - it('arranges custom gutters based on their priority', async (done) => { + it('arranges custom gutters based on their priority', async () => { const { component, editor } = buildComponent(); editor.addGutter({ name: 'e', priority: 2 }); editor.addGutter({ name: 'a', priority: -2 }); @@ -2857,11 +2729,9 @@ describe('TextEditorComponent', () => { expect( Array.from(gutters).map(g => g.getAttribute('gutter-name')) ).toEqual(['a', 'b', 'c', 'line-number', 'd', 'e']); - - done(); }); - it('adjusts the left edge of the scroll container based on changes to the gutter container width', async (done) => { + it('adjusts the left edge of the scroll container based on changes to the gutter container width', async () => { const { component, editor } = buildComponent(); const { scrollContainer, gutterContainer } = component.refs; @@ -2899,11 +2769,9 @@ describe('TextEditorComponent', () => { gutterB.destroy(); await component.getNextUpdatePromise(); checkScrollContainerLeft(); - - done(); }); - it('allows the element of custom gutters to be retrieved before being rendered in the editor component', async (done) => { + it('allows the element of custom gutters to be retrieved before being rendered in the editor component', async () => { const { component, element, editor } = buildComponent(); const [lineNumberGutter] = editor.getGutters(); const gutterA = editor.addGutter({ name: 'a', priority: -1 }); @@ -2918,11 +2786,9 @@ describe('TextEditorComponent', () => { expect(element.contains(lineNumberGutterElement)).toBe(true); expect(element.contains(gutterAElement)).toBe(true); expect(element.contains(gutterBElement)).toBe(true); - - done(); }); - it('can show and hide custom gutters', async (done) => { + it('can show and hide custom gutters', async () => { const { component, editor } = buildComponent(); const gutterA = editor.addGutter({ name: 'a', priority: -1 }); const gutterB = editor.addGutter({ name: 'b', priority: 1 }); @@ -2947,11 +2813,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); expect(gutterAElement.style.display).toBe(''); expect(gutterBElement.style.display).toBe('none'); - - done(); }); - it('renders decorations in custom gutters', async (done) => { + 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 }); @@ -3043,11 +2907,9 @@ describe('TextEditorComponent', () => { expect(decorationNode2.className).toBe('decoration'); expect(decorationNode2.firstChild).toBeNull(); expect(gutterB.getElement().firstChild.children.length).toBe(0); - - done(); }); - it('renders custom line number gutters', async (done) => { + it('renders custom line number gutters', async () => { const { component, editor } = buildComponent(); const gutterA = editor.addGutter({ name: 'a', @@ -3094,8 +2956,6 @@ describe('TextEditorComponent', () => { 'b - 4', 'b - 5' ]); - - done(); }); it("updates the editor's soft wrap width when a custom gutter's measurement is available", () => { @@ -3122,7 +2982,7 @@ describe('TextEditorComponent', () => { }); describe('block decorations', () => { - it('renders visible block decorations between the appropriate lines, refreshing and measuring them as needed', async (done) => { + it('renders visible block decorations between the appropriate lines, refreshing and measuring them as needed', async () => { const editor = buildEditor({ autoHeight: false }); const { item: item1, @@ -3533,11 +3393,9 @@ describe('TextEditorComponent', () => { expect(item5.previousSibling).toBe(lineNodeForScreenRow(component, 7)); expect(item5.nextSibling).toBe(lineNodeForScreenRow(component, 8)); expect(item6.previousSibling).toBe(lineNodeForScreenRow(component, 12)); - - done(); }); - it('correctly positions line numbers when block decorations are located at tile boundaries', async (done) => { + it('correctly positions line numbers when block decorations are located at tile boundaries', async () => { const { editor, component } = buildComponent({ rowsPerTile: 3 }); createBlockDecorationAtScreenRow(editor, 0, { height: 5, @@ -3570,11 +3428,9 @@ describe('TextEditorComponent', () => { }, { tileStartRow: 6, height: 3 * component.getLineHeight() } ]); - - done(); }); - it('removes block decorations whose markers have been destroyed', async (done) => { + it('removes block decorations whose markers have been destroyed', async () => { const { editor, component } = buildComponent({ rowsPerTile: 3 }); const { marker } = createBlockDecorationAtScreenRow(editor, 2, { height: 5, @@ -3596,11 +3452,9 @@ describe('TextEditorComponent', () => { { tileStartRow: 3, height: 3 * component.getLineHeight() }, { tileStartRow: 6, height: 3 * component.getLineHeight() } ]); - - done(); }); - it('removes block decorations whose markers are invalidated, and adds them back when they become valid again', async (done) => { + 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, @@ -3655,11 +3509,9 @@ describe('TextEditorComponent', () => { { tileStartRow: 3, height: 3 * component.getLineHeight() }, { tileStartRow: 6, height: 3 * component.getLineHeight() } ]); - - done(); }); - it('does not render block decorations when decorating invalid markers', async (done) => { + it('does not render block decorations when decorating invalid markers', async () => { const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }); const { component } = buildComponent({ editor, rowsPerTile: 3 }); @@ -3695,11 +3547,9 @@ describe('TextEditorComponent', () => { { tileStartRow: 3, height: 3 * component.getLineHeight() }, { tileStartRow: 6, height: 3 * component.getLineHeight() } ]); - - done(); }); - it('does not try to remeasure block decorations whose markers are invalid (regression)', async (done) => { + it('does not try to remeasure block decorations whose markers are invalid (regression)', async () => { const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }); const { component } = buildComponent({ editor, rowsPerTile: 3 }); createBlockDecorationAtScreenRow(editor, 2, { @@ -3717,11 +3567,9 @@ describe('TextEditorComponent', () => { { tileStartRow: 3, height: 3 * component.getLineHeight() }, { tileStartRow: 6, height: 3 * component.getLineHeight() } ]); - - done(); }); - it('does not throw exceptions when destroying a block decoration inside a marker change event (regression)', async (done) => { + it('does not throw exceptions when destroying a block decoration inside a marker change event (regression)', async () => { const { editor, component } = buildComponent({ rowsPerTile: 3 }); const marker = editor.markScreenPosition([2, 0]); @@ -3739,11 +3587,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); expect(item.parentElement).toBeNull(); - - done(); }); - it('does not attempt to render block decorations located outside the visible range', async (done) => { + it('does not attempt to render block decorations located outside the visible range', async () => { const { editor, component } = buildComponent({ autoHeight: false, rowsPerTile: 2 @@ -3773,11 +3619,9 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(8); expect(item1.nextSibling).toBe(lineNodeForScreenRow(component, 5)); expect(item2.parentElement).toBeNull(); - - done(); }); - it('measures block decorations correctly when they are added before the component width has been updated', async (done) => { + it('measures block decorations correctly when they are added before the component width has been updated', async () => { { const { editor, component, element } = buildComponent({ autoHeight: false, @@ -3813,11 +3657,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); assertLinesAreAlignedWithLineNumbers(component); } - - done(); }); - it('bases the width of the block decoration measurement area on the editor scroll width', async (done) => { + it('bases the width of the block decoration measurement area on the editor scroll width', async () => { const { component, element } = buildComponent({ autoHeight: false, width: 150 @@ -3831,11 +3673,9 @@ describe('TextEditorComponent', () => { expect(component.refs.blockDecorationMeasurementArea.offsetWidth).toBe( component.getScrollWidth() ); - - done(); }); - it('does not change the cursor position when clicking on a block decoration', async (done) => { + it('does not change the cursor position when clicking on a block decoration', async () => { const { editor, component } = buildComponent(); const decorationElement = document.createElement('div'); @@ -3866,11 +3706,9 @@ describe('TextEditorComponent', () => { clientY: childElementClientRect.top }); expect(editor.getCursorScreenPosition()).toEqual([0, 0]); - - done(); }); - it('uses the order property to control the order of block decorations at the same screen row', async (done) => { + 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 = @@ -3976,8 +3814,6 @@ describe('TextEditorComponent', () => { expect(beforeItems[5].nextSibling).toBe( lineNodeForScreenRow(component, 2) ); - - done(); }); function createBlockDecorationAtScreenRow( @@ -4040,7 +3876,7 @@ describe('TextEditorComponent', () => { }); describe('cursor decorations', () => { - it('allows default cursors to be customized', async (done) => { + it('allows default cursors to be customized', async () => { const { component, element, editor } = buildComponent(); editor.addCursorAtScreenPosition([1, 0]); @@ -4067,11 +3903,9 @@ describe('TextEditorComponent', () => { expect(cursorNodes[1].className).toBe('cursor b'); expect(cursorNodes[1].style.visibility).toBe('hidden'); expect(cursorNodes[1].style.backgroundColor).toBe('red'); - - done(); }); - it('allows markers that are not actually associated with cursors to be decorated as if they were cursors', async (done) => { + 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 marker = editor.markScreenPosition([1, 0]); editor.decorateMarker(marker, { type: 'cursor', class: 'a' }); @@ -4081,13 +3915,11 @@ describe('TextEditorComponent', () => { expect(cursorNodes.length).toBe(2); expect(cursorNodes[0].className).toBe('cursor'); expect(cursorNodes[1].className).toBe('cursor a'); - - done(); }); }); describe('text decorations', () => { - it('injects spans with custom class names and inline styles based on text decorations', async (done) => { + it('injects spans with custom class names and inline styles based on text decorations', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 2 }); const markerLayer = editor.addMarkerLayer(); @@ -4159,11 +3991,9 @@ describe('TextEditorComponent', () => { expect(textContentOnRowMatchingSelector(component, 3, '.b')).toBe( editor.lineTextForScreenRow(3).slice(0, 10) ); - - done(); }); - it('correctly handles text decorations starting before the first rendered row and/or ending after the last rendered row', async (done) => { + 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 @@ -4198,11 +4028,9 @@ describe('TextEditorComponent', () => { expect(textContentOnRowMatchingSelector(component, 8, '.b')).toBe( editor.lineTextForScreenRow(8) ); - - done(); }); - 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 (done) => { + 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 markerLayer = editor.addMarkerLayer(); const marker1 = markerLayer.markBufferRange([[0, 2], [4, 0]]); @@ -4213,11 +4041,9 @@ describe('TextEditorComponent', () => { for (const decorationSpan of element.querySelectorAll('.a, .b')) { expect(decorationSpan.textContent).not.toBe(''); } - - done(); }); - it('does not create empty text nodes when a text decoration ends right after a text tag', async (done) => { + it('does not create empty text nodes when a text decoration ends right after a text tag', async () => { const { component, editor } = buildComponent(); const marker = editor.markBufferRange([[0, 8], [0, 29]]); editor.decorateMarker(marker, { type: 'text', class: 'a' }); @@ -4225,8 +4051,6 @@ describe('TextEditorComponent', () => { for (const textNode of textNodesForScreenRow(component, 0)) { expect(textNode.textContent).not.toBe(''); } - - done(); }); function textContentOnRowMatchingSelector(component, row, selector) { @@ -4241,7 +4065,7 @@ describe('TextEditorComponent', () => { describe('mouse input', () => { describe('on the lines', () => { describe('when there is only one cursor', () => { - it('positions the cursor on single-click or when middle-clicking', async (done) => { + it('positions the cursor on single-click or when middle-clicking', async () => { atom.config.set('editor.selectionClipboard', false); for (const button of [0, 1]) { const { component, editor } = buildComponent(); @@ -4356,8 +4180,6 @@ describe('TextEditorComponent', () => { expect(editor.testAutoscrollRequests).toEqual([]); } - - done(); }); }); @@ -4877,7 +4699,7 @@ describe('TextEditorComponent', () => { expect(editor.getSelectedScreenRange()).toEqual([[2, 0], [5, 0]]); }); - it('destroys folds when clicking on their fold markers', async (done) => { + it('destroys folds when clicking on their fold markers', async () => { const { component, element, editor } = buildComponent(); editor.foldBufferRow(1); await component.getNextUpdatePromise(); @@ -4897,11 +4719,9 @@ describe('TextEditorComponent', () => { }); expect(editor.isFoldedAtBufferRow(1)).toBe(false); expect(editor.getCursorScreenPosition()).toEqual([0, 0]); - - done(); }); - it('autoscrolls the content when dragging near the edge of the scroll container', async (done) => { + it('autoscrolls the content when dragging near the edge of the scroll container', async () => { const { component } = buildComponent({ width: 200, height: 200 @@ -4978,12 +4798,10 @@ describe('TextEditorComponent', () => { didDrag({ clientX: 199, clientY: 199 }); expect(component.getScrollTop()).toBeNear(maxScrollTop); expect(component.getScrollLeft()).toBeNear(maxScrollLeft); - - done(); }); }); - it('pastes the previously selected text when clicking the middle mouse button on Linux', async (done) => { + it('pastes the previously selected text when clicking the middle mouse button on Linux', async () => { spyOn(electron.ipcRenderer, 'send').and.callFake(function( eventName, selectedText @@ -5035,11 +4853,9 @@ describe('TextEditorComponent', () => { clientY: clientTopForLine(component, 10) }); expect(editor.lineTextForBufferRow(10)).toBe('var'); - - done(); }); - it('does not paste into a read only editor when clicking the middle mouse button on Linux', async (done) => { + it('does not paste into a read only editor when clicking the middle mouse button on Linux', async () => { spyOn(electron.ipcRenderer, 'send').and.callFake(function( eventName, selectedText @@ -5068,13 +4884,11 @@ describe('TextEditorComponent', () => { // Ensure that the correct text was copied but not pasted expect(TextEditor.clipboard.read()).toBe('sort'); expect(editor.lineTextForBufferRow(10)).toBe(''); - - done(); }); }); describe('on the line number gutter', () => { - it('selects all buffer rows intersecting the clicked screen row when a line number is clicked', async (done) => { + it('selects all buffer rows intersecting the clicked screen row when a line number is clicked', async () => { const { component, editor } = buildComponent(); spyOn(component, 'handleMouseDragUntilMouseUp'); editor.setSoftWrapped(true); @@ -5100,11 +4914,9 @@ describe('TextEditorComponent', () => { }); expect(editor.getSelectedScreenRange()).toEqual([[5, 0], [6, 0]]); expect(editor.getSelectedBufferRange()).toEqual([[4, 0], [8, 0]]); - - done(); }); - it('adds new selections when a line number is meta-clicked', async (done) => { + it('adds new selections when a line number is meta-clicked', async () => { const { component, editor } = buildComponent(); editor.setSoftWrapped(true); await component.getNextUpdatePromise(); @@ -5145,11 +4957,9 @@ describe('TextEditorComponent', () => { [[3, 0], [4, 0]], [[4, 0], [8, 0]] ]); - - done(); }); - it('expands the last selection when a line number is shift-clicked', async (done) => { + it('expands the last selection when a line number is shift-clicked', async () => { const { component, editor } = buildComponent(); spyOn(component, 'handleMouseDragUntilMouseUp'); editor.setSoftWrapped(true); @@ -5191,11 +5001,9 @@ describe('TextEditorComponent', () => { didStopDragging(); expect(editor.getSelectedBufferRanges()).toEqual([[[2, 10], [8, 0]]]); - - done(); }); - it('expands the selection when dragging', async (done) => { + it('expands the selection when dragging', async () => { const { component, editor } = buildComponent(); spyOn(component, 'handleMouseDragUntilMouseUp'); editor.setSoftWrapped(true); @@ -5245,11 +5053,9 @@ describe('TextEditorComponent', () => { didStopDragging(); expect(editor.getSelectedScreenRanges()).toEqual([[[2, 0], [4, 4]]]); - - done(); }); - it('toggles folding when clicking on the right icon of a foldable line number', async (done) => { + 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] @@ -5285,11 +5091,9 @@ describe('TextEditorComponent', () => { clientY: clientTopForLine(component, 4) }); expect(editor.isFoldedAtScreenRow(4)).toBe(false); - - done(); }); - it('autoscrolls when dragging near the top or bottom of the gutter', async (done) => { + it('autoscrolls when dragging near the top or bottom of the gutter', async () => { const { component } = buildComponent({ width: 200, height: 200 @@ -5364,13 +5168,11 @@ describe('TextEditorComponent', () => { didDrag({ clientX: 199, clientY: 199 }); expect(component.getScrollTop()).toBeNear(maxScrollTop); expect(component.getScrollLeft()).toBeNear(maxScrollLeft); - - done(); }); }); describe('on the scrollbars', () => { - it('delegates the mousedown events to the parent component unless the mousedown was on the actual scrollbar', async (done) => { + it('delegates the mousedown events to the parent component unless the mousedown was on the actual scrollbar', async () => { const { component, editor } = buildComponent({ height: 100 }); await setEditorWidthInCharacters(component, 6); @@ -5414,8 +5216,6 @@ describe('TextEditorComponent', () => { clientX: component.refs.content.getBoundingClientRect().left }); expect(editor.getCursorScreenPosition()).toEqual([4, 0]); - - done(); }); }); }); @@ -5733,7 +5533,7 @@ describe('TextEditorComponent', () => { * Expected 7.234375 not to be 7.234375. * Expected 7.234375 not to be 7.234375. */ - xit('updates the rendered content based on new measurements when the font dimensions change', async (done) => { + xit('updates the rendered content based on new measurements when the font dimensions change', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 1, autoHeight: false @@ -5799,11 +5599,9 @@ describe('TextEditorComponent', () => { initialRenderedLineCount ); verifyCursorPosition(component, cursorNode, 1, 29); - - done(); }); - it('maintains the scrollTopRow and scrollLeftColumn when the font size changes', async (done) => { + it('maintains the scrollTopRow and scrollLeftColumn when the font size changes', async () => { const { component, element } = buildComponent({ rowsPerTile: 1, autoHeight: false @@ -5824,11 +5622,9 @@ describe('TextEditorComponent', () => { TextEditor.didUpdateStyles(); await component.getNextUpdatePromise(); expect(component.getScrollTopRow()).toBe(4); - - done(); }); - it('gracefully handles the editor being hidden after a styling change', async (done) => { + it('gracefully handles the editor being hidden after a styling change', async () => { const { component, element } = buildComponent({ autoHeight: false }); @@ -5837,11 +5633,9 @@ describe('TextEditorComponent', () => { TextEditor.didUpdateStyles(); element.style.display = 'none'; await component.getNextUpdatePromise(); - - done(); }); - it('does not throw an exception when the editor is soft-wrapped and changing the font size changes also the longest screen line', async (done) => { + 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 @@ -5859,11 +5653,9 @@ describe('TextEditorComponent', () => { element.style.fontSize = '20px'; TextEditor.didUpdateStyles(); await component.getNextUpdatePromise(); - - done(); }); - it('updates the width of the lines div based on the longest screen line', async (done) => { + it('updates the width of the lines div based on the longest screen line', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 1, autoHeight: false @@ -5888,8 +5680,6 @@ describe('TextEditorComponent', () => { component.getBaseCharacterWidth() ); expect(actualWidth).toBe(expectedWidth + 'px'); - - done(); }); }); @@ -5959,7 +5749,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 (done) => { + it('returns the pixel position for the given point, regardless of whether or not it is currently on screen', async () => { const { component, editor } = buildComponent({ rowsPerTile: 2, autoHeight: false @@ -6028,11 +5818,9 @@ describe('TextEditorComponent', () => { referenceContentRect.left ); } - - done(); }); - it('does not get the component into an inconsistent state when the model has unflushed changes (regression)', async (done) => { + it('does not get the component into an inconsistent state when the model has unflushed changes (regression)', async () => { const { component, editor } = buildComponent({ rowsPerTile: 2, autoHeight: false, @@ -6043,11 +5831,9 @@ describe('TextEditorComponent', () => { const updatePromise = editor.getBuffer().append('hi\n'); component.screenPositionForPixelPosition({ top: 800, left: 1 }); await updatePromise; - - done(); }); - it('does not shift cursors downward or render off-screen content when measuring off-screen lines (regression)', async (done) => { + it('does not shift cursors downward or render off-screen content when measuring off-screen lines (regression)', async () => { const { component, element } = buildComponent({ rowsPerTile: 2, autoHeight: false @@ -6073,13 +5859,11 @@ describe('TextEditorComponent', () => { ); expect(previouslyMeasuredLineElement.style.display).toBe(''); expect(previouslyMeasuredLineElement.style.visibility).toBe(''); - - done(); }); }); describe('screenPositionForPixelPosition', () => { - it('returns the screen position for the given pixel position, regardless of whether or not it is currently on screen', async (done) => { + it('returns the screen position for the given pixel position, regardless of whether or not it is currently on screen', async () => { const { component, editor } = buildComponent({ rowsPerTile: 2, autoHeight: false @@ -6145,13 +5929,11 @@ describe('TextEditorComponent', () => { [3, 4] ); } - - done(); }); }); describe('model methods that delegate to the component / element', () => { - it('delegates setHeight and getHeight to the component', async (done) => { + it('delegates setHeight and getHeight to the component', async () => { const { component, editor } = buildComponent({ autoHeight: false }); @@ -6163,11 +5945,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); expect(component.getScrollContainerHeight()).toBe(100); expect(Grim.deprecate.calls.count()).toBe(2); - - done(); }); - it('delegates setWidth and getWidth to the component', async (done) => { + it('delegates setWidth and getWidth to the component', async () => { const { component, editor } = buildComponent(); spyOn(Grim, 'deprecate'); expect(editor.getWidth()).toBe(component.getScrollContainerWidth()); @@ -6177,11 +5957,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise(); expect(component.getScrollContainerWidth()).toBe(100); expect(Grim.deprecate.calls.count()).toBe(2); - - done(); }); - it('delegates getFirstVisibleScreenRow, getLastVisibleScreenRow, and getVisibleRowRange to the component', async (done) => { + it('delegates getFirstVisibleScreenRow, getLastVisibleScreenRow, and getVisibleRowRange to the component', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 3, autoHeight: false @@ -6200,11 +5978,9 @@ describe('TextEditorComponent', () => { component.getFirstVisibleRow(), component.getLastVisibleRow() ]); - - done(); }); - it('assigns scrollTop on the component when calling setFirstVisibleScreenRow', async (done) => { + it('assigns scrollTop on the component when calling setFirstVisibleScreenRow', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 3, autoHeight: false @@ -6242,11 +6018,9 @@ describe('TextEditorComponent', () => { expect(component.refs.verticalScrollbar.element.scrollTop).toBeNear( 9 * component.getLineHeight() ); - - done(); }); - it('delegates setFirstVisibleScreenColumn and getFirstVisibleScreenColumn to the component', async (done) => { + it('delegates setFirstVisibleScreenColumn and getFirstVisibleScreenColumn to the component', async () => { const { component, element, editor } = buildComponent({ rowsPerTile: 3, autoHeight: false @@ -6274,13 +6048,11 @@ describe('TextEditorComponent', () => { 12 * component.getBaseCharacterWidth(), -1 ); - - done(); }); }); describe('handleMouseDragUntilMouseUp', () => { - it('repeatedly schedules `didDrag` calls on new animation frames after moving the mouse, and calls `didStopDragging` on mouseup', async (done) => { + it('repeatedly schedules `didDrag` calls on new animation frames after moving the mouse, and calls `didStopDragging` on mouseup', async () => { const { component } = buildComponent(); let dragEvents; @@ -6327,11 +6099,9 @@ describe('TextEditorComponent', () => { await getNextAnimationFramePromise(); expect(dragging).toBe(false); expect(dragEvents).toEqual([]); - - done(); }); - it('calls `didStopDragging` if the user interacts with the keyboard while dragging', async (done) => { + it('calls `didStopDragging` if the user interacts with the keyboard while dragging', async () => { const { component, editor } = buildComponent(); let dragging = false; @@ -6373,8 +6143,6 @@ describe('TextEditorComponent', () => { component.didKeydown({ key: 'Shift' }); component.didKeydown({ key: 'Meta' }); expect(dragging).toBe(true); - - done(); }); function getNextAnimationFramePromise() { diff --git a/spec/text-editor-element-spec.js b/spec/text-editor-element-spec.js index 9be4393538..16d3b997c7 100644 --- a/spec/text-editor-element-spec.js +++ b/spec/text-editor-element-spec.js @@ -70,7 +70,7 @@ describe('TextEditorElement', () => { expect(element.getModel().isLineNumberGutterVisible()).toBe(false); }); - it("honors the 'readonly' attribute", async function(done) { + it("honors the 'readonly' attribute", async function() { jasmineContent.innerHTML = ''; const element = jasmineContent.firstChild; @@ -81,8 +81,6 @@ describe('TextEditorElement', () => { element.setAttribute('readonly', true); expect(element.getComponent().isInputEnabled()).toBe(false); - - done(); }); it('honors the text content', () => { @@ -108,13 +106,11 @@ describe('TextEditorElement', () => { }); describe('when the model is assigned', () => - it("adds the 'mini' attribute if .isMini() returns true on the model", async (done) => { + it("adds the 'mini' attribute if .isMini() returns true on the model", async () => { const element = buildTextEditorElement(); element.getModel().update({ mini: true }); await atom.views.getNextUpdatePromise(); expect(element.hasAttribute('mini')).toBe(true); - - done(); })); describe('when the editor is attached to the DOM', () => @@ -274,7 +270,7 @@ describe('TextEditorElement', () => { }); describe('when the element already has an editor', () => { - it('unbinds it and then swaps it with the supplied one', async (done) => { + it('unbinds it and then swaps it with the supplied one', async () => { const element = buildTextEditorElement({ attach: true }); const previousEditor = element.getModel(); expect(previousEditor.element).toBe(element); @@ -284,8 +280,6 @@ describe('TextEditorElement', () => { expect(previousEditor.element).not.toBe(element); expect(newEditor.element).toBe(element); expect(element.getModel()).toBe(newEditor); - - done(); }); }); }); @@ -346,7 +340,7 @@ describe('TextEditorElement', () => { }); describe('::getMaxScrollTop', () => - it('returns the maximum scroll top that can be applied to the element', async (done) => { + it('returns the maximum scroll top that can be applied to the element', async () => { const editor = new TextEditor(); editor.setText('1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16'); const element = editor.getElement(); @@ -370,12 +364,10 @@ describe('TextEditorElement', () => { element.style.height = 200 + horizontalScrollbarHeight + 'px'; await element.getNextUpdatePromise(); expect(element.getMaxScrollTop()).toBe(0); - - done(); })); describe('::setScrollTop and ::setScrollLeft', () => { - it('changes the scroll position', async (done) => { + it('changes the scroll position', async () => { const element = buildTextEditorElement(); element.getModel().update({ autoHeight: false }); element.getModel().setText('lorem\nipsum\ndolor\nsit\namet'); @@ -391,13 +383,11 @@ describe('TextEditorElement', () => { element.setScrollLeft(32); await element.getNextUpdatePromise(); expect(element.getScrollLeft()).toBe(32); - - done(); }); }); describe('on TextEditor::setMini', () => - it("changes the element's 'mini' attribute", async (done) => { + it("changes the element's 'mini' attribute", async () => { const element = buildTextEditorElement(); expect(element.hasAttribute('mini')).toBe(false); element.getModel().setMini(true); @@ -406,12 +396,10 @@ describe('TextEditorElement', () => { element.getModel().setMini(false); await element.getNextUpdatePromise(); expect(element.hasAttribute('mini')).toBe(false); - - done(); })); describe('::intersectsVisibleRowRange(start, end)', () => { - it('returns true if the given row range intersects the visible row range', async (done) => { + it('returns true if the given row range intersects the visible row range', async () => { const element = buildTextEditorElement(); const editor = element.getModel(); const horizontalScrollbarHeight = element.component.getHorizontalScrollbarHeight(); @@ -430,13 +418,11 @@ describe('TextEditorElement', () => { expect(element.intersectsVisibleRowRange(5, 8)).toBe(true); expect(element.intersectsVisibleRowRange(11, 12)).toBe(false); expect(element.intersectsVisibleRowRange(12, 13)).toBe(false); - - done(); }); }); describe('::pixelRectForScreenRange(range)', () => { - it('returns a {top/left/width/height} object describing the rectangle between two screen positions, even if they are not on screen', async (done) => { + it('returns a {top/left/width/height} object describing the rectangle between two screen positions, even if they are not on screen', async () => { const element = buildTextEditorElement(); const editor = element.getModel(); const horizontalScrollbarHeight = element.component.getHorizontalScrollbarHeight(); @@ -462,15 +448,13 @@ describe('TextEditorElement', () => { bottom + editor.getLineHeightInPixels() - top ); expect(pixelRect.width).toBeNear(right - left); - - done(); }); }); describe('events', () => { let element = null; - beforeEach(async (done) => { + beforeEach(async () => { element = buildTextEditorElement(); element.getModel().update({ autoHeight: false }); element.getModel().setText('lorem\nipsum\ndolor\nsit\namet'); @@ -478,8 +462,6 @@ describe('TextEditorElement', () => { await element.getNextUpdatePromise(); element.setWidth(20); await element.getNextUpdatePromise(); - - done(); }); describe('::onDidChangeScrollTop(callback)', () => diff --git a/spec/text-editor-registry-spec.js b/spec/text-editor-registry-spec.js index c306c491fe..5d958d9ef9 100644 --- a/spec/text-editor-registry-spec.js +++ b/spec/text-editor-registry-spec.js @@ -110,7 +110,7 @@ describe('TextEditorRegistry', function() { }); describe('.maintainConfig(editor)', function() { - it('does not update the editor when config settings change for unrelated scope selectors', async function(done) { + it('does not update the editor when config settings change for unrelated scope selectors', async function() { await atom.packages.activatePackage('language-javascript'); const editor2 = new TextEditor(); @@ -140,11 +140,9 @@ describe('TextEditorRegistry', function() { expect(editor.getEncoding()).toBe('utf16le'); expect(editor2.getEncoding()).toBe('utf16be'); - - done(); }); - it('does not update the editor before the initial packages have loaded', async function(done) { + it('does not update the editor before the initial packages have loaded', async function() { let resolveActivatePromise; initialPackageActivation = new Promise(resolve => { resolveActivatePromise = resolve; @@ -163,11 +161,9 @@ describe('TextEditorRegistry', function() { resolveActivatePromise(); await initialPackageActivation; expect(editor.getEncoding()).toBe('utf16be'); - - done(); }); - it("updates the editor's settings when its grammar changes", async function(done) { + it("updates the editor's settings when its grammar changes", async function() { await atom.packages.activatePackage('language-javascript'); registry.maintainConfig(editor); @@ -195,11 +191,9 @@ describe('TextEditorRegistry', function() { atom.grammars.assignLanguageMode(editor, 'text.plain.null-grammar'); await initialPackageActivation; expect(editor.getEncoding()).toBe('utf8'); - - done(); }); - it("preserves editor settings that haven't changed between previous and current language modes", async function(done) { + 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); @@ -217,11 +211,9 @@ describe('TextEditorRegistry', function() { await initialPackageActivation; expect(editor.getEncoding()).toBe('utf16le'); expect(editor.isSoftWrapped()).toBe(true); - - done(); }); - it('updates editor settings that have changed between previous and current language modes', async function(done) { + it('updates editor settings that have changed between previous and current language modes', async function() { await atom.packages.activatePackage('language-javascript'); registry.maintainConfig(editor); @@ -242,11 +234,9 @@ describe('TextEditorRegistry', function() { atom.grammars.assignLanguageMode(editor, 'source.js'); await initialPackageActivation; expect(editor.getEncoding()).toBe('utf16le'); - - done(); }); - it("returns a disposable that can be used to stop the registry from updating the editor's config", async function(done) { + 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); @@ -268,11 +258,9 @@ describe('TextEditorRegistry', function() { expect(editor.getEncoding()).toBe('utf8'); expect(getSubscriptionCount(editor)).toBe(previousSubscriptionCount); expect(retainedEditorCount(registry)).toBe(0); - - done(); }); - it('sets the encoding based on the config', async function(done) { + it('sets the encoding based on the config', async function() { editor.update({ encoding: 'utf8' }); expect(editor.getEncoding()).toBe('utf8'); @@ -283,11 +271,9 @@ describe('TextEditorRegistry', function() { atom.config.set('core.fileEncoding', 'utf8'); expect(editor.getEncoding()).toBe('utf8'); - - done(); }); - it('sets the tab length based on the config', async function(done) { + it('sets the tab length based on the config', async function() { editor.update({ tabLength: 4 }); expect(editor.getTabLength()).toBe(4); @@ -298,30 +284,24 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.tabLength', 4); expect(editor.getTabLength()).toBe(4); - - done(); }); - it('enables soft tabs when the tabType config setting is "soft"', async function(done) { + it('enables soft tabs when the tabType config setting is "soft"', async function() { atom.config.set('editor.tabType', 'soft'); registry.maintainConfig(editor); await initialPackageActivation; expect(editor.getSoftTabs()).toBe(true); - - done(); }); - it('disables soft tabs when the tabType config setting is "hard"', async function(done) { + it('disables soft tabs when the tabType config setting is "hard"', async function() { atom.config.set('editor.tabType', 'hard'); registry.maintainConfig(editor); await initialPackageActivation; expect(editor.getSoftTabs()).toBe(false); - - done(); }); describe('when the "tabType" config setting is "auto"', function() { - it("enables or disables soft tabs based on the editor's content", async function(done) { + 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'); @@ -388,13 +368,11 @@ describe('TextEditorRegistry', function() { disposable.dispose(); disposable = registry.maintainConfig(editor); expect(editor.getSoftTabs()).toBe(true); - - done(); }); }); describe('when the "tabType" config setting is "auto"', function() { - it('enables or disables soft tabs based on the "softTabs" config setting', async function(done) { + it('enables or disables soft tabs based on the "softTabs" config setting', async function() { registry.maintainConfig(editor); await initialPackageActivation; @@ -405,12 +383,10 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.softTabs', false); expect(editor.getSoftTabs()).toBe(false); - - done(); }); }); - it('enables or disables soft tabs based on the config', async function(done) { + it('enables or disables soft tabs based on the config', async function() { editor.update({ softTabs: true }); expect(editor.getSoftTabs()).toBe(true); @@ -425,11 +401,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.tabType', 'auto'); atom.config.set('editor.softTabs', true); expect(editor.getSoftTabs()).toBe(true); - - done(); }); - it('enables or disables atomic soft tabs based on the config', async function(done) { + it('enables or disables atomic soft tabs based on the config', async function() { editor.update({ atomicSoftTabs: true }); expect(editor.hasAtomicSoftTabs()).toBe(true); @@ -440,11 +414,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.atomicSoftTabs', true); expect(editor.hasAtomicSoftTabs()).toBe(true); - - done(); }); - it('enables or disables cursor on selection visibility based on the config', async function(done) { + it('enables or disables cursor on selection visibility based on the config', async function() { editor.update({ showCursorOnSelection: true }); expect(editor.getShowCursorOnSelection()).toBe(true); @@ -455,11 +427,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.showCursorOnSelection', true); expect(editor.getShowCursorOnSelection()).toBe(true); - - done(); }); - it('enables or disables line numbers based on the config', async function(done) { + it('enables or disables line numbers based on the config', async function() { editor.update({ showLineNumbers: true }); expect(editor.showLineNumbers).toBe(true); @@ -470,11 +440,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.showLineNumbers', true); expect(editor.showLineNumbers).toBe(true); - - done(); }); - it('sets the invisibles based on the config', async function(done) { + 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 }; @@ -495,11 +463,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.showInvisibles', false); expect(editor.getInvisibles()).toEqual({}); - - done(); }); - it('enables or disables the indent guide based on the config', async function(done) { + it('enables or disables the indent guide based on the config', async function() { editor.update({ showIndentGuide: true }); expect(editor.doesShowIndentGuide()).toBe(true); @@ -510,11 +476,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.showIndentGuide', true); expect(editor.doesShowIndentGuide()).toBe(true); - - done(); }); - it('enables or disables soft wrap based on the config', async function(done) { + it('enables or disables soft wrap based on the config', async function() { editor.update({ softWrapped: true }); expect(editor.isSoftWrapped()).toBe(true); @@ -525,11 +489,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.softWrap', true); expect(editor.isSoftWrapped()).toBe(true); - - done(); }); - it('sets the soft wrap indent length based on the config', async function(done) { + it('sets the soft wrap indent length based on the config', async function() { editor.update({ softWrapHangingIndentLength: 4 }); expect(editor.getSoftWrapHangingIndentLength()).toBe(4); @@ -540,11 +502,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.softWrapHangingIndent', 4); expect(editor.getSoftWrapHangingIndentLength()).toBe(4); - - done(); }); - it('enables or disables preferred line length-based soft wrap based on the config', async function(done) { + it('enables or disables preferred line length-based soft wrap based on the config', async function() { editor.update({ softWrapped: true, preferredLineLength: 80, @@ -562,11 +522,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.softWrapAtPreferredLineLength', true); expect(editor.getSoftWrapColumn()).toBe(80); - - done(); }); - it('allows for custom definition of maximum soft wrap based on config', async function(done) { + it('allows for custom definition of maximum soft wrap based on config', async function() { editor.update({ softWrapped: false, maxScreenLineLength: 1500 @@ -579,11 +537,9 @@ describe('TextEditorRegistry', function() { registry.maintainConfig(editor); await initialPackageActivation; expect(editor.getSoftWrapColumn()).toBe(500); - - done(); }); - it('sets the preferred line length based on the config', async function(done) { + it('sets the preferred line length based on the config', async function() { editor.update({ preferredLineLength: 80 }); expect(editor.getPreferredLineLength()).toBe(80); @@ -594,11 +550,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.preferredLineLength', 80); expect(editor.getPreferredLineLength()).toBe(80); - - done(); }); - it('enables or disables auto-indent based on the config', async function(done) { + it('enables or disables auto-indent based on the config', async function() { editor.update({ autoIndent: true }); expect(editor.shouldAutoIndent()).toBe(true); @@ -609,11 +563,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.autoIndent', true); expect(editor.shouldAutoIndent()).toBe(true); - - done(); }); - it('enables or disables auto-indent-on-paste based on the config', async function(done) { + it('enables or disables auto-indent-on-paste based on the config', async function() { editor.update({ autoIndentOnPaste: true }); expect(editor.shouldAutoIndentOnPaste()).toBe(true); @@ -624,11 +576,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.autoIndentOnPaste', true); expect(editor.shouldAutoIndentOnPaste()).toBe(true); - - done(); }); - it('enables or disables scrolling past the end of the buffer based on the config', async function(done) { + it('enables or disables scrolling past the end of the buffer based on the config', async function() { editor.update({ scrollPastEnd: true }); expect(editor.getScrollPastEnd()).toBe(true); @@ -639,11 +589,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.scrollPastEnd', true); expect(editor.getScrollPastEnd()).toBe(true); - - done(); }); - it('sets the undo grouping interval based on the config', async function(done) { + it('sets the undo grouping interval based on the config', async function() { editor.update({ undoGroupingInterval: 300 }); expect(editor.getUndoGroupingInterval()).toBe(300); @@ -654,11 +602,9 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.undoGroupingInterval', 300); expect(editor.getUndoGroupingInterval()).toBe(300); - - done(); }); - it('sets the scroll sensitivity based on the config', async function(done) { + it('sets the scroll sensitivity based on the config', async function() { editor.update({ scrollSensitivity: 50 }); expect(editor.getScrollSensitivity()).toBe(50); @@ -669,12 +615,10 @@ describe('TextEditorRegistry', function() { atom.config.set('editor.scrollSensitivity', 70); expect(editor.getScrollSensitivity()).toBe(70); - - done(); }); describe('when called twice with a given editor', function() { - it('does nothing the second time', async function(done) { + it('does nothing the second time', async function() { editor.update({ scrollSensitivity: 50 }); const disposable1 = registry.maintainConfig(editor); @@ -691,8 +635,6 @@ describe('TextEditorRegistry', function() { disposable1.dispose(); atom.config.set('editor.scrollSensitivity', 80); expect(editor.getScrollSensitivity()).toBe(70); - - done(); }); }); }); diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 30e644f655..262642772e 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -19,7 +19,7 @@ async function languageModeReady(editor) { describe('TextEditor', () => { let buffer, editor, lineLengths, languageMode; - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('sample.js'); buffer = editor.buffer; editor.update({ autoIndent: false }); @@ -33,19 +33,15 @@ describe('TextEditor', () => { if (languageMode.ready) { await languageMode.ready; } - - done(); }); - afterEach(async (done) => { + afterEach(async () => { if (languageMode?.atTransactionEnd) { await languageMode.atTransactionEnd(); } - - done(); }) - it('generates unique ids for each editor', async (done) => { + 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 }); @@ -54,12 +50,10 @@ describe('TextEditor', () => { // The id generator should skip the id used up by the deserialized one: const fresh = new TextEditor(); expect(fresh.id).not.toEqual(deserialized.id); - - done(); }); describe('when the editor is deserialized', () => { - it('restores selections and folds based on markers in the buffer', async (done) => { + 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.foldBufferRow(4); @@ -85,11 +79,9 @@ describe('TextEditor', () => { expect(editor2.getSelections()[1].isReversed()).toBeTruthy(); expect(editor2.isFoldedAtBufferRow(4)).toBeTruthy(); editor2.destroy(); - - done(); }); - it("restores the editor's layout configuration", async (done) => { + it("restores the editor's layout configuration", async () => { editor.update({ softTabs: true, atomicSoftTabs: false, @@ -130,8 +122,6 @@ describe('TextEditor', () => { expect(editor2.displayLayer.softWrapColumn).toBe( editor2.getSoftWrapColumn() ); - - done(); }); it('ignores buffers with retired IDs', () => { @@ -250,7 +240,7 @@ describe('TextEditor', () => { expect(editor.getLongTitle()).toBe('untitled'); }); - it("returns '' when opened files have identical file names", async (done) => { + it("returns '' when opened files have identical file names", async () => { const editor1 = await atom.workspace.open( path.join('sample-theme-1', 'readme') ); @@ -259,22 +249,18 @@ describe('TextEditor', () => { ); expect(editor1.getLongTitle()).toBe('readme \u2014 sample-theme-1'); expect(editor2.getLongTitle()).toBe('readme \u2014 sample-theme-2'); - - done(); }); - it("returns '' when opened files have identical file names in subdirectories", async (done) => { + it("returns '' when opened files have identical file names in subdirectories", async () => { const path1 = path.join('sample-theme-1', 'src', 'js'); const path2 = path.join('sample-theme-2', 'src', 'js'); const editor1 = await atom.workspace.open(path.join(path1, 'main.js')); const editor2 = await atom.workspace.open(path.join(path2, 'main.js')); expect(editor1.getLongTitle()).toBe(`main.js \u2014 ${path1}`); expect(editor2.getLongTitle()).toBe(`main.js \u2014 ${path2}`); - - done(); }); - it("returns '' when opened files have identical file and same parent dir name", async (done) => { + 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') ); @@ -285,19 +271,15 @@ describe('TextEditor', () => { expect(editor2.getLongTitle()).toBe( `main.js \u2014 ${path.join('js', 'plugin')}` ); - - done(); }); - it('returns the filename when the editor is not in the workspace', async (done) => { + it('returns the filename when the editor is not in the workspace', async () => { editor.onDidDestroy(() => { expect(editor.getLongTitle()).toBe('sample.js'); }); await atom.workspace.getActivePane().close(); expect(editor.isDestroyed()).toBe(true); - - done(); }); }); @@ -2512,7 +2494,7 @@ describe('TextEditor', () => { ]); }); - it('takes atomic tokens into account', async (done) => { + it('takes atomic tokens into account', async () => { editor = await atom.workspace.open( 'sample-with-tabs-and-leading-comment.coffee', { autoIndent: false } @@ -2523,8 +2505,6 @@ describe('TextEditor', () => { [[2, 1], [2, 3]], [[3, 1], [3, 2]] ]); - - done(); }); }); @@ -2654,7 +2634,7 @@ describe('TextEditor', () => { ]); }); - it('takes atomic tokens into account', async (done) => { + it('takes atomic tokens into account', async () => { editor = await atom.workspace.open( 'sample-with-tabs-and-leading-comment.coffee', { autoIndent: false } @@ -2665,8 +2645,6 @@ describe('TextEditor', () => { [[3, 1], [3, 2]], [[2, 1], [2, 3]] ]); - - done(); }); }); @@ -2835,7 +2813,7 @@ describe('TextEditor', () => { }); }); - it('does not share selections between different edit sessions for the same buffer', async (done) => { + it('does not share selections between different edit sessions for the same buffer', async () => { atom.workspace.getActivePane().splitRight(); const editor2 = await atom.workspace.open(editor.getPath()); @@ -2845,8 +2823,6 @@ describe('TextEditor', () => { expect(editor2.getSelectedBufferRanges()).not.toEqual( editor.getSelectedBufferRanges() ); - - done(); }); }); @@ -3252,12 +3228,10 @@ describe('TextEditor', () => { }); describe('when there are many folds', () => { - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('sample-with-many-folds.js', { autoIndent: false }); - - done(); }); describe('and many selections intersects folded rows', () => @@ -3690,12 +3664,10 @@ describe('TextEditor', () => { })); describe('when there are many folds', () => { - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('sample-with-many-folds.js', { autoIndent: false }); - - done(); }); describe('and many selections intersects folded rows', () => @@ -4209,15 +4181,13 @@ describe('TextEditor', () => { }); }); - it("inserts a newline below the cursor's current line, autoindents it, and moves the cursor to the end of the line", async (done) => { + it("inserts a newline below the cursor's current line, autoindents it, and moves the cursor to the end of the line", async () => { editor.update({ autoIndent: true }); editor.insertNewlineBelow(); await languageMode.atTransactionEnd(); expect(buffer.lineForRow(0)).toBe('var quicksort = function () {'); expect(buffer.lineForRow(1)).toBe(' '); expect(editor.getCursorBufferPosition()).toEqual([1, 2]); - - done(); }); }); @@ -4314,7 +4284,7 @@ describe('TextEditor', () => { expect(editor.indentationForBufferRow(1)).toBe(1); }); - it('indents the new line to the correct level when editor.autoIndent is true and using an off-side rule language', async (done) => { + 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 }); atom.grammars.assignLanguageMode(editor, 'source.coffee'); @@ -4324,13 +4294,11 @@ describe('TextEditor', () => { expect(editor.indentationForBufferRow(1)).toBe(1); expect(editor.indentationForBufferRow(2)).toBe(0); expect(editor.indentationForBufferRow(3)).toBe(1); - - done(); }); }); 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 (done) => { + 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 }); atom.grammars.assignLanguageMode(editor, 'source.go'); @@ -4339,8 +4307,6 @@ describe('TextEditor', () => { editor.insertNewline(); expect(editor.indentationForBufferRow(1)).toBe(1); expect(editor.indentationForBufferRow(2)).toBe(0); - - done(); }); }); }); @@ -5411,7 +5377,7 @@ describe('TextEditor', () => { }); describe('when pasting line(s) above a line that matches the decreaseIndentPattern', () => - it('auto-indents based on the pasted line(s) only', async (done) => { + it('auto-indents based on the pasted line(s) only', async () => { atom.clipboard.write('a(x);\n b(x);\n c(x);\n', { indentBasis: 0 }); @@ -5423,8 +5389,6 @@ describe('TextEditor', () => { expect(editor.lineTextForBufferRow(8)).toBe(' b(x);'); expect(editor.lineTextForBufferRow(9)).toBe(' c(x);'); expect(editor.lineTextForBufferRow(10)).toBe(' }'); - - done(); })); describe('when pasting a line of text without line ending', () => @@ -6025,7 +5989,7 @@ describe('TextEditor', () => { describe('undo/redo restore selections of editor which initiated original change', () => { let editor1, editor2; - beforeEach(async (done) => { + beforeEach(async () => { editor1 = editor; editor2 = new TextEditor({ buffer: editor1.buffer }); @@ -6036,8 +6000,6 @@ describe('TextEditor', () => { dddddd eeeeee `); - - done(); }); it('[editor.transact] restore selection of change-initiated-editor', () => { @@ -6887,7 +6849,7 @@ describe('TextEditor', () => { }); - it('notifies onDidTokenize observers when retokenization is finished', async (done) => { + it('notifies onDidTokenize observers when retokenization is finished', async () => { // Exercise the full `tokenizeInBackground` code path, which bails out early if // `.setVisible` has not been called with `true`. jasmine.unspy(TextMateLanguageMode.prototype, 'tokenizeInBackground'); @@ -6902,11 +6864,9 @@ describe('TextEditor', () => { ).toBe(true); advanceClock(1); expect(events.length).toBe(1); - - done(); }); - it('notifies onDidChangeGrammar observers', async (done) => { + it('notifies onDidChangeGrammar observers', async () => { const events = []; editor.onDidChangeGrammar(grammar => events.push(grammar)); @@ -6916,8 +6876,6 @@ describe('TextEditor', () => { ).toBe(true); expect(events.length).toBe(1); expect(events[0].name).toBe('C'); - - done(); }); }); @@ -6973,14 +6931,12 @@ describe('TextEditor', () => { }); describe('when the line preceding the newline is a comment', () => { - it('maintains the indent of the commented line', async (done) => { + it('maintains the indent of the commented line', async () => { editor.setCursorBufferPosition([0, 0]); editor.insertText(' //'); editor.setCursorBufferPosition([0, Infinity]); editor.insertText('\n'); expect(editor.indentationForBufferRow(1)).toBe(2); - - done(); }); }); @@ -7446,16 +7402,14 @@ describe('TextEditor', () => { }); describe("when the editor's grammar has an injection selector", () => { - beforeEach(async (done) => { + beforeEach(async () => { atom.config.set('core.useTreeSitterParsers', false); await atom.packages.activatePackage('language-text'); await atom.packages.activatePackage('language-javascript'); - - done(); }); - it("includes the grammar's patterns when the selector matches the current scope in other grammars", async (done) => { + it("includes the grammar's patterns when the selector matches the current scope in other grammars", async () => { await atom.packages.activatePackage('language-hyperlink'); const grammar = atom.grammars.selectGrammar('text.js'); @@ -7472,12 +7426,10 @@ describe('TextEditor', () => { 'comment.line.double-slash.js', 'markup.underline.link.http.hyperlink' ]); - - done(); }); describe('when the grammar is added', () => { - it('retokenizes existing buffers that contain tokens that match the injection selector', async (done) => { + it('retokenizes existing buffers that contain tokens that match the injection selector', async () => { editor = await atom.workspace.open('sample.js'); editor.setText('// http://github.com'); let tokens = editor.tokensForScreenRow(0); @@ -7526,12 +7478,10 @@ describe('TextEditor', () => { ] } ]); - - done(); }); describe('when the grammar is updated', () => { - it('retokenizes existing buffers that contain tokens that match the injection selector', async (done) => { + it('retokenizes existing buffers that contain tokens that match the injection selector', async () => { editor = await atom.workspace.open('sample.js'); editor.setText('// SELECT * FROM OCTOCATS'); let tokens = editor.tokensForScreenRow(0); @@ -7639,8 +7589,6 @@ describe('TextEditor', () => { ] } ]); - - done(); }); }); }); @@ -8264,7 +8212,7 @@ describe('TextEditor', () => { }); describe('.getCommentDelimitersForBufferPosition', () => { - it('returns comment delimiters on a TextMate grammar', async (done) => { + it('returns comment delimiters on a TextMate grammar', async () => { atom.config.set('core.useTreeSitterParsers', false); editor = await atom.workspace.open('sample.js', { autoIndent: false }); @@ -8289,11 +8237,9 @@ describe('TextEditor', () => { line: '//', block: ['/*', '*/'] }) - - done(); }) - it('returns comment delimiters on a modern Tree-sitter grammar', async (done) => { + it('returns comment delimiters on a modern Tree-sitter grammar', async () => { jasmine.useRealClock(); atom.config.set('core.useTreeSitterParsers', true); @@ -8320,13 +8266,11 @@ describe('TextEditor', () => { line: '//', block: ['/*', '*/'] }) - - done(); }) }) describe('.syntaxTreeScopeDescriptorForBufferPosition(position)', () => { - it('returns the result of scopeDescriptorForBufferPosition() when textmate language mode is used', async (done) => { + 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 }); @@ -8353,11 +8297,9 @@ describe('TextEditor', () => { 'source.js', 'support.variable.property.js' ]); - - done(); }); - it('returns the result of syntaxTreeScopeDescriptorForBufferPosition() when tree-sitter language mode is used', async (done) => { + it('returns the result of syntaxTreeScopeDescriptorForBufferPosition() when tree-sitter language mode is used', async () => { jasmine.useRealClock(); editor = await atom.workspace.open('sample.js', { autoIndent: false }); await atom.packages.activatePackage('language-javascript'); @@ -8396,18 +8338,14 @@ describe('TextEditor', () => { 'member_expression', 'property_identifier' ]); - - done(); }); }); describe('.shouldPromptToSave()', () => { - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('sample.js'); jasmine.unspy(editor, 'shouldPromptToSave'); spyOn(atom.stateStore, 'isConnected').and.returnValue(true); - - done(); }); it('returns true when buffer has unsaved changes', () => { @@ -8416,7 +8354,7 @@ describe('TextEditor', () => { expect(editor.shouldPromptToSave()).toBeTruthy(); }); - it("returns false when an editor's buffer is in use by more than one buffer", async (done) => { + it("returns false when an editor's buffer is in use by more than one buffer", async () => { editor.setText('changed'); atom.workspace.getActivePane().splitRight(); @@ -8427,11 +8365,9 @@ describe('TextEditor', () => { editor2.destroy(); expect(editor.shouldPromptToSave()).toBeTruthy(); - - done(); }); - it('returns true when the window is closing if the file has changed on disk', async (done) => { + it('returns true when the window is closing if the file has changed on disk', async () => { jasmine.useRealClock(); editor.setText('initial stuff'); @@ -8453,8 +8389,6 @@ describe('TextEditor', () => { projectHasPaths: true }) ).toBeTruthy(); - - done(); }); it('returns false when the window is closing and the project has one or more directory paths', () => { @@ -8479,11 +8413,9 @@ describe('TextEditor', () => { }); describe('.toggleLineCommentsInSelection()', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('language-javascript'); editor = await atom.workspace.open('sample.js'); - - done(); }); it('toggles comments on the selected lines', () => { @@ -8642,12 +8574,10 @@ describe('TextEditor', () => { describe('.toggleLineCommentsForBufferRows', () => { describe('xml', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('language-xml'); editor = await atom.workspace.open('test.xml'); editor.setText(''); - - done(); }); it('removes the leading whitespace from the comment end pattern match when uncommenting lines', () => { @@ -8723,12 +8653,10 @@ describe('TextEditor', () => { }); describe('less', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('language-less'); await atom.packages.activatePackage('language-css'); editor = await atom.workspace.open('sample.less'); - - done(); }); it('only uses the `commentEnd` pattern if it comes from the same grammar as the `commentStart` when commenting lines', () => { @@ -8738,11 +8666,9 @@ describe('TextEditor', () => { }); describe('css', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('language-css'); editor = await atom.workspace.open('css.css'); - - done(); }); it('comments/uncomments lines in the given range', () => { @@ -8800,11 +8726,9 @@ describe('TextEditor', () => { }); describe('coffeescript', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('language-coffee-script'); editor = await atom.workspace.open('coffee.coffee'); - - done(); }); it('comments/uncomments lines in the given range', () => { @@ -8843,11 +8767,9 @@ describe('TextEditor', () => { }); describe('javascript', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('language-javascript'); editor = await atom.workspace.open('sample.js'); - - done(); }); it('comments/uncomments lines in the given range', () => { @@ -8906,23 +8828,19 @@ describe('TextEditor', () => { }); describe('folding', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('language-javascript'); - - done(); }); - it('maintains cursor buffer position when a folding/unfolding', async (done) => { + it('maintains cursor buffer position when a folding/unfolding', async () => { editor = await atom.workspace.open('sample.js', { autoIndent: false }); editor.setCursorBufferPosition([5, 5]); editor.foldAll(); expect(editor.getCursorBufferPosition()).toEqual([5, 5]); - - done(); }); describe('.unfoldAll()', () => { - it('unfolds every folded line', async (done) => { + it('unfolds every folded line', async () => { editor = await atom.workspace.open('sample.js', { autoIndent: false }); await languageModeReady(editor); @@ -8934,11 +8852,9 @@ describe('TextEditor', () => { ); editor.unfoldAll(); expect(editor.getScreenLineCount()).toBe(initialScreenLineCount); - - done(); }); - it('unfolds every folded line with comments', async (done) => { + it('unfolds every folded line with comments', async () => { editor = await atom.workspace.open('sample-with-comments.js', { autoIndent: false }); @@ -8952,13 +8868,11 @@ describe('TextEditor', () => { ); editor.unfoldAll(); expect(editor.getScreenLineCount()).toBe(initialScreenLineCount); - - done(); }); }); describe('.foldAll()', () => { - it('folds every foldable line', async (done) => { + it('folds every foldable line', async () => { editor = await atom.workspace.open('sample.js', { autoIndent: false }); await languageModeReady(editor); @@ -8967,17 +8881,13 @@ describe('TextEditor', () => { expect([fold1.start.row, fold1.end.row]).toEqual([0, 12]); expect([fold2.start.row, fold2.end.row]).toEqual([1, 9]); expect([fold3.start.row, fold3.end.row]).toEqual([4, 7]); - - done(); }); }); describe('.foldBufferRow(bufferRow)', () => { - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('sample.js'); await languageModeReady(editor); - - done(); }); describe('when bufferRow can be folded', () => { @@ -9018,31 +8928,27 @@ describe('TextEditor', () => { }); describe('.foldCurrentRow()', () => { - it('creates a fold at the location of the last cursor', async (done) => { + it('creates a fold at the location of the last cursor', async () => { editor = await atom.workspace.open(); editor.setText('\nif (x) {\n y()\n}'); editor.setCursorBufferPosition([1, 0]); expect(editor.getScreenLineCount()).toBe(4); editor.foldCurrentRow(); expect(editor.getScreenLineCount()).toBe(3); - - done(); }); - it('does nothing when the current row cannot be folded', async (done) => { + it('does nothing when the current row cannot be folded', async () => { editor = await atom.workspace.open(); editor.setText('var x;\nx++\nx++'); editor.setCursorBufferPosition([0, 0]); expect(editor.getScreenLineCount()).toBe(3); editor.foldCurrentRow(); expect(editor.getScreenLineCount()).toBe(3); - - done(); }); }); describe('.foldAllAtIndentLevel(indentLevel)', () => { - it('folds blocks of text at the given indentation level', async (done) => { + it('folds blocks of text at the given indentation level', async () => { editor = await atom.workspace.open('sample.js', { autoIndent: false }); await languageModeReady(editor); @@ -9072,11 +8978,9 @@ describe('TextEditor', () => { ' if (items.length <= 1) return items;' ); expect(editor.getLastScreenRow()).toBe(9); - - done(); }); - it('does not fold anything but the indentLevel', async (done) => { + it('does not fold anything but the indentLevel', async () => { editor = await atom.workspace.open('sample-with-comments.js', { autoIndent: false }); @@ -9086,8 +8990,6 @@ describe('TextEditor', () => { const folds = editor.unfoldAll(); expect(folds.length).toBe(1); expect([folds[0].start.row, folds[0].end.row]).toEqual([0, 30]); - - done(); }); }); }); diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index 666981cea4..3b46f76f54 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -8,15 +8,13 @@ const dedent = require('dedent'); describe('TextMateLanguageMode', () => { let languageMode, buffer, config; - beforeEach(async (done) => { + beforeEach(async () => { config = atom.config; config.set('core.useTreeSitterParsers', false); // enable async tokenization TextMateLanguageMode.prototype.chunkSize = 5; jasmine.unspy(TextMateLanguageMode.prototype, 'tokenizeInBackground'); await atom.packages.activatePackage('language-javascript'); - - done(); }); afterEach(() => { @@ -26,7 +24,7 @@ describe('TextMateLanguageMode', () => { }); describe('when the editor is constructed with the largeFileMode option set to true', () => { - it("loads the editor but doesn't tokenize", async (done) => { + it("loads the editor but doesn't tokenize", async () => { const line = 'a b c d\n'; buffer = new TextBuffer(line.repeat(256 * 1024)); expect(buffer.getText().length).toBe(2 * 1024 * 1024); @@ -50,8 +48,6 @@ describe('TextMateLanguageMode', () => { iterator.seek({ row: 0, column: 0 }); iterator.moveToSuccessor(); expect(iterator.getPosition()).toEqual({ row: 0, column: 11 }); - - done(); }); }); @@ -431,7 +427,7 @@ describe('TextMateLanguageMode', () => { }); describe('when the buffer contains hard-tabs', () => { - beforeEach(async (done) => { + beforeEach(async () => { atom.packages.activatePackage('language-coffee-script'); buffer = atom.project.bufferForPathSync('sample-with-tabs.coffee'); @@ -441,8 +437,6 @@ describe('TextMateLanguageMode', () => { grammar: atom.grammars.grammarForScopeName('source.coffee') }); languageMode.startTokenizing(); - - done(); }); afterEach(() => { @@ -456,18 +450,16 @@ describe('TextMateLanguageMode', () => { }); describe('when tokenization completes', () => { - it('emits the `tokenized` event', async (done) => { + it('emits the `tokenized` event', async () => { const editor = await atom.workspace.open('sample.js'); const tokenizedHandler = jasmine.createSpy('tokenized handler'); editor.languageMode.onDidTokenize(tokenizedHandler); fullyTokenize(editor.getBuffer().getLanguageMode()); expect(tokenizedHandler.calls.count()).toBe(1); - - done(); }); - it("doesn't re-emit the `tokenized` event when it is re-tokenized", async (done) => { + it("doesn't re-emit the `tokenized` event when it is re-tokenized", async () => { const editor = await atom.workspace.open('sample.js'); fullyTokenize(editor.languageMode); @@ -476,13 +468,11 @@ describe('TextMateLanguageMode', () => { editor.getBuffer().insert([0, 0], "'"); fullyTokenize(editor.languageMode); expect(tokenizedHandler).not.toHaveBeenCalled(); - - done(); }); }); describe('when the grammar is updated because a grammar it includes is activated', () => { - it('re-emits the `tokenized` event', async (done) => { + it('re-emits the `tokenized` event', async () => { let tokenizationCount = 0; const editor = await atom.workspace.open('coffee.coffee'); @@ -495,11 +485,9 @@ describe('TextMateLanguageMode', () => { await atom.packages.activatePackage('language-coffee-script'); fullyTokenize(editor.getBuffer().getLanguageMode()); expect(tokenizationCount).toBe(1); - - done(); }); - it('retokenizes the buffer', async (done) => { + it('retokenizes the buffer', async () => { await atom.packages.activatePackage('language-ruby-on-rails'); await atom.packages.activatePackage('language-ruby'); @@ -527,8 +515,6 @@ describe('TextMateLanguageMode', () => { 'punctuation.definition.tag.begin.html' ] }); - - done(); }); }); @@ -846,7 +832,7 @@ describe('TextMateLanguageMode', () => { iterator.moveToSuccessor(); }); // ensure we don't infinitely loop (regression test) - it('does not report columns beyond the length of the line', async (done) => { + 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' }); @@ -871,8 +857,6 @@ describe('TextMateLanguageMode', () => { iterator.seek(Point(0, 8)); expect(iterator.getPosition().column).toBe(7); - - done(); }); it('correctly terminates scopes at the beginning of the line (regression)', () => { @@ -1014,11 +998,9 @@ describe('TextMateLanguageMode', () => { let editor; describe('javascript', () => { - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('sample.js', { autoIndent: false }); await atom.packages.activatePackage('language-javascript'); - - done(); }); it('bases indentation off of the previous non-blank line', () => { @@ -1044,12 +1026,10 @@ describe('TextMateLanguageMode', () => { }); describe('css', () => { - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('css.css', { autoIndent: true }); await atom.packages.activatePackage('language-source'); await atom.packages.activatePackage('language-css'); - - done(); }); it('does not return negative values (regression)', () => { @@ -1137,7 +1117,7 @@ describe('TextMateLanguageMode', () => { expect(languageMode.isFoldableAtRow(8)).toBe(false); }); - it('returns true if the line starts a multi-line comment', async (done) => { + it('returns true if the line starts a multi-line comment', async () => { editor = await atom.workspace.open('sample-with-comments.js'); fullyTokenize(editor.getBuffer().getLanguageMode()); @@ -1150,27 +1130,21 @@ describe('TextMateLanguageMode', () => { expect(editor.isFoldableAtBufferRow(21)).toBe(true); expect(editor.isFoldableAtBufferRow(24)).toBe(true); expect(editor.isFoldableAtBufferRow(28)).toBe(false); - - done(); }); - it('returns true for lines that end with a comment and are followed by an indented line', async (done) => { + it('returns true for lines that end with a comment and are followed by an indented line', async () => { editor = await atom.workspace.open('sample-with-comments.js'); expect(editor.isFoldableAtBufferRow(5)).toBe(true); - - done(); }); - it("does not return true for a line in the middle of a comment that's followed by an indented line", async (done) => { + it("does not return true for a line in the middle of a comment that's followed by an indented line", async () => { editor = await atom.workspace.open('sample-with-comments.js'); fullyTokenize(editor.getBuffer().getLanguageMode()); expect(editor.isFoldableAtBufferRow(7)).toBe(false); editor.buffer.insert([8, 0], ' '); expect(editor.isFoldableAtBufferRow(7)).toBe(false); - - done(); }); }); @@ -1240,7 +1214,7 @@ describe('TextMateLanguageMode', () => { `); }); - it('folds every foldable range at a given indentLevel', async (done) => { + it('folds every foldable range at a given indentLevel', async () => { editor = await atom.workspace.open('sample-with-comments.js'); fullyTokenize(editor.getBuffer().getLanguageMode()); @@ -1252,8 +1226,6 @@ describe('TextMateLanguageMode', () => { expect([folds[2].start.row, folds[2].end.row]).toEqual([17, 20]); expect([folds[3].start.row, folds[3].end.row]).toEqual([21, 22]); expect([folds[4].start.row, folds[4].end.row]).toEqual([24, 25]); - - done(); }); }); @@ -1290,7 +1262,7 @@ describe('TextMateLanguageMode', () => { ); }); - it('works with multi-line comments', async (done) => { + it('works with multi-line comments', async () => { await atom.packages.activatePackage('language-javascript'); const editor = await atom.workspace.open('sample-with-comments.js', { autoIndent: false @@ -1308,8 +1280,6 @@ describe('TextMateLanguageMode', () => { expect([folds[5].start.row, folds[5].end.row]).toEqual([17, 20]); expect([folds[6].start.row, folds[6].end.row]).toEqual([21, 22]); expect([folds[7].start.row, folds[7].end.row]).toEqual([24, 25]); - - done(); }); }); @@ -1391,7 +1361,7 @@ describe('TextMateLanguageMode', () => { `); }); - it('works for coffee-script', async (done) => { + it('works for coffee-script', async () => { const editor = await atom.workspace.open('coffee.coffee'); await atom.packages.activatePackage('language-coffee-script'); buffer = editor.buffer; @@ -1409,11 +1379,9 @@ describe('TextMateLanguageMode', () => { expect( languageMode.getFoldableRangeContainingPoint(Point(19, Infinity), 2) ).toEqual([[19, Infinity], [20, Infinity]]); - - done(); }); - it('works for javascript', async (done) => { + it('works for javascript', async () => { const editor = await atom.workspace.open('sample.js'); await atom.packages.activatePackage('language-javascript'); buffer = editor.buffer; @@ -1443,11 +1411,9 @@ describe('TextMateLanguageMode', () => { 2 ) ).toEqual([[4, Infinity], [7, Infinity]]); - - done(); }); - it('searches upward and downward for surrounding comment lines and folds them as a single fold', async (done) => { + it('searches upward and downward for surrounding comment lines and folds them as a single fold', async () => { await atom.packages.activatePackage('language-javascript'); const editor = await atom.workspace.open('sample-with-comments.js'); editor.buffer.insert( @@ -1458,8 +1424,6 @@ describe('TextMateLanguageMode', () => { editor.foldBufferRow(1); const [fold] = editor.unfoldAll(); expect([fold.start.row, fold.end.row]).toEqual([1, 3]); - - done(); }); }); diff --git a/spec/theme-manager-spec.js b/spec/theme-manager-spec.js index 1be8284cb4..8a135f8861 100644 --- a/spec/theme-manager-spec.js +++ b/spec/theme-manager-spec.js @@ -8,14 +8,12 @@ describe('atom.themes', function() { spyOn(console, 'warn'); }); - afterEach(async function(done) { + afterEach(async function() { await atom.themes.deactivateThemes(); try { temp.cleanupSync(); } catch (error) {} - - done(); }); describe('theme getters and setters', function() { @@ -33,15 +31,13 @@ describe('atom.themes', function() { })); describe('getActiveThemes', () => - it('gets all the active themes', async function(done) { + it('gets all the active themes', async function() { await atom.themes.activateThemes(); const names = atom.config.get('core.themes'); expect(names.length).toBeGreaterThan(0); const themes = atom.themes.getActiveThemes(); expect(themes).toHaveLength(names.length); - - done(); })); }); @@ -88,7 +84,7 @@ describe('atom.themes', function() { }); describe('when the core.themes config value changes', function() { - it('add/removes stylesheets to reflect the new config value', async function(done) { + it('add/removes stylesheets to reflect the new config value', async function() { let didChangeActiveThemesHandler = jasmine.createSpy(); atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler); spyOn(atom.styles, 'getUserStyleSheetPath').and.callFake(() => null); @@ -152,11 +148,9 @@ describe('atom.themes', function() { const importPaths = atom.themes.getImportPaths(); expect(importPaths.length).toBe(1); expect(importPaths[0]).toContain('atom-dark-ui'); - - done(); }); - it('adds theme-* classes to the workspace for each active theme', async function(done) { + it('adds theme-* classes to the workspace for each active theme', async function() { atom.config.set('core.themes', ['atom-dark-ui', 'atom-dark-syntax']); let didChangeActiveThemesHandler = jasmine.createSpy(); @@ -186,8 +180,6 @@ describe('atom.themes', function() { ); expect(workspaceElement).not.toHaveClass('theme-atom-dark-ui'); expect(workspaceElement).not.toHaveClass('theme-atom-dark-syntax'); - - done(); }); }); @@ -332,17 +324,15 @@ h2 { }); describe('base style sheet loading', function() { - beforeEach(async function(done) { + beforeEach(async function() { const workspaceElement = atom.workspace.getElement(); jasmine.attachToDOM(atom.workspace.getElement()); workspaceElement.appendChild(document.createElement('atom-text-editor')); await atom.themes.activateThemes(); - - done(); }); - it("loads the correct values from the theme's ui-variables file", async function(done) { + it("loads the correct values from the theme's ui-variables file", async function() { await new Promise((resolve) => { atom.themes.onDidChangeActiveThemes(resolve); atom.config.set('core.themes', [ @@ -369,12 +359,10 @@ h2 { getComputedStyle(document.querySelector('atom-text-editor')) .paddingBottom ).toBe('150px'); - - done(); }); describe('when there is a theme with incomplete variables', () => - it('loads the correct values from the fallback ui-variables', async function(done) { + it('loads the correct values from the fallback ui-variables', async function() { await new Promise((resolve) => { atom.themes.onDidChangeActiveThemes(resolve); atom.config.set('core.themes', [ @@ -393,8 +381,6 @@ h2 { getComputedStyle(document.querySelector('atom-text-editor')) .backgroundColor ).toBe('rgb(0, 152, 255)'); - - done(); })); }); @@ -414,7 +400,7 @@ h2 { afterEach(() => jasmine.restoreDeprecationsSnapshot()); - it('reloads it', async function(done) { + it('reloads it', async function() { let styleElementAddedHandler = jasmine.createSpy('styleElementRemovedHandler'); let styleElementRemovedHandler = jasmine.createSpy('styleElementAddedHandler'); @@ -463,8 +449,6 @@ h2 { styleElementRemovedHandler.calls.argsFor(0)[0].textContent ).toContain('dashed'); expect(getComputedStyle(document.body).borderStyle).toBe('none'); - - done(); }); }); @@ -534,7 +518,7 @@ h2 { }); describe('when a non-existent theme is present in the config', function() { - beforeEach(async function(done) { + beforeEach(async function() { console.warn.calls.reset(); atom.config.set('core.themes', [ 'non-existent-dark-ui', @@ -542,8 +526,6 @@ h2 { ]); await atom.themes.activateThemes(); - - done(); }); it('uses the default one-dark UI and syntax themes and logs a warning', function() { @@ -557,12 +539,10 @@ h2 { describe('when in safe mode', function() { describe('when the enabled UI and syntax themes are bundled with Atom', function() { - beforeEach(async function(done) { + beforeEach(async function() { atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-syntax']); await atom.themes.activateThemes(); - - done(); }); it('uses the enabled themes', function() { @@ -574,15 +554,13 @@ h2 { }); describe('when the enabled UI and syntax themes are not bundled with Atom', function() { - beforeEach(async function(done) { + beforeEach(async function() { atom.config.set('core.themes', [ 'installed-dark-ui', 'installed-dark-syntax' ]); await atom.themes.activateThemes(); - - done(); }); it('uses the default dark UI and syntax themes', function() { @@ -594,15 +572,13 @@ h2 { }); describe('when the enabled UI theme is not bundled with Atom', function() { - beforeEach(async function(done) { + beforeEach(async function() { atom.config.set('core.themes', [ 'installed-dark-ui', 'atom-light-syntax' ]); await atom.themes.activateThemes(); - - done(); }); it('uses the default one-dark UI theme', function() { @@ -614,15 +590,13 @@ h2 { }); describe('when the enabled syntax theme is not bundled with Atom', function() { - beforeEach(async function(done) { + beforeEach(async function() { atom.config.set('core.themes', [ 'atom-light-ui', 'installed-dark-syntax' ]); await atom.themes.activateThemes(); - - done(); }); it('uses the default one-dark syntax theme', function() { diff --git a/spec/tree-indenter-spec.js b/spec/tree-indenter-spec.js index 0e67386733..d59dcf104b 100644 --- a/spec/tree-indenter-spec.js +++ b/spec/tree-indenter-spec.js @@ -49,7 +49,7 @@ describe('TreeIndenter', () => { let editor, buffer, grammar; let languageMode, treeIndenter; - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open(''); buffer = editor.getBuffer(); editor.displayLayer.reset({ foldCharacter: '…' }); @@ -57,8 +57,6 @@ describe('TreeIndenter', () => { grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript' }); - - done(); }); /** load a file from disk and verify that our proposed indentation diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index 29ab519ce2..26567c3566 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -37,14 +37,12 @@ const rustGrammarPath = require.resolve( describe('TreeSitterLanguageMode', () => { let editor, buffer; - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open(''); buffer = editor.getBuffer(); editor.displayLayer.reset({ foldCharacter: '…' }); atom.config.set('core.useTreeSitterParsers', true); atom.config.set('core.useLegacyTreeSitter', true); - - done(); }); describe('highlighting', () => { @@ -464,7 +462,7 @@ describe('TreeSitterLanguageMode', () => { }); describe('when the buffer changes during a parse', () => { - it('immediately parses again when the current parse completes', async (done) => { + it('immediately parses again when the current parse completes', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { @@ -526,8 +524,6 @@ describe('TreeSitterLanguageMode', () => { { text: '();', scopes: [] } ] ]); - - done(); }); }); @@ -607,7 +603,7 @@ describe('TreeSitterLanguageMode', () => { }); }); - it('highlights code inside of injection points', async (done) => { + it('highlights code inside of injection points', async () => { atom.grammars.addGrammar(jsGrammar); atom.grammars.addGrammar(htmlGrammar); buffer.setText('node.innerHTML = html `\na ${b}\n`;'); @@ -664,8 +660,6 @@ describe('TreeSitterLanguageMode', () => { ], [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]); - - done(); }); it('highlights the content after injections', () => { @@ -708,7 +702,7 @@ describe('TreeSitterLanguageMode', () => { ]); }); - it('updates buffers highlighting when a grammar with injectionRegExp is added', async (done) => { + it('updates buffers highlighting when a grammar with injectionRegExp is added', async () => { atom.grammars.addGrammar(jsGrammar); buffer.setText('node.innerHTML = html `\na ${b}\n`;'); @@ -762,8 +756,6 @@ describe('TreeSitterLanguageMode', () => { ], [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]); - - done(); }); it('handles injections that intersect', () => { @@ -845,7 +837,7 @@ describe('TreeSitterLanguageMode', () => { ]); }); - it('handles injections that are empty', async (done) => { + it('handles injections that are empty', async () => { atom.grammars.addGrammar(jsGrammar); atom.grammars.addGrammar(htmlGrammar); buffer.setText('text = html'); @@ -900,8 +892,6 @@ describe('TreeSitterLanguageMode', () => { { text: ';', scopes: [] } ] ]); - - done(); }); it('terminates comment token at the end of an injection, so that the next injection is NOT a continuation of the comment', () => { @@ -994,7 +984,7 @@ describe('TreeSitterLanguageMode', () => { ]); }); - it('reports scopes from shallower layers when they are at the start or end of an injection', async (done) => { + it('reports scopes from shallower layers when they are at the start or end of an injection', async () => { await atom.packages.activatePackage('language-javascript'); editor.setGrammar(atom.grammars.grammarForScopeName('source.js')); @@ -1031,8 +1021,6 @@ describe('TreeSitterLanguageMode', () => { } ] ]); - - done(); }); it('respects the `includeChildren` property of injection points', () => { @@ -1110,7 +1098,7 @@ describe('TreeSitterLanguageMode', () => { ]); }); - it('notifies onDidTokenize listeners the first time all syntax highlighting is done', async (done) => { + it('notifies onDidTokenize listeners the first time all syntax highlighting is done', async () => { const promise = new Promise(resolve => { editor.onDidTokenize(event => { expectTokensToEqual(editor, [ @@ -1146,8 +1134,6 @@ describe('TreeSitterLanguageMode', () => { buffer.setLanguageMode(languageMode); await promise; - - done(); }); }); }); @@ -1164,7 +1150,7 @@ describe('TreeSitterLanguageMode', () => { jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; }); - it('matches the highlighting of a freshly-opened editor', async (done) => { + it('matches the highlighting of a freshly-opened editor', async () => { jasmine.useRealClock(); const text = fs.readFileSync( @@ -1239,8 +1225,6 @@ describe('TreeSitterLanguageMode', () => { expect(tokens1).toEqual(tokens2, `Seed: ${seed}, screen line: ${j}`); } } - - done(); }); }); diff --git a/spec/update-process-env-spec.js b/spec/update-process-env-spec.js index 69adc32074..e18f29811f 100644 --- a/spec/update-process-env-spec.js +++ b/spec/update-process-env-spec.js @@ -36,7 +36,7 @@ describe('updateProcessEnv(launchEnv)', function() { }); describe('when the launch environment appears to come from a shell', function() { - it('updates process.env to match the launch environment because PWD is set', async function(done) { + it('updates process.env to match the launch environment because PWD is set', async function() { process.env = { WILL_BE_DELETED: 'hi', NODE_ENV: 'the-node-env', @@ -68,11 +68,9 @@ describe('updateProcessEnv(launchEnv)', function() { // case-insensitive environment variable matching, so we cannot replace it // with another object. expect(process.env).toBe(initialProcessEnv); - - done(); }); - it('updates process.env to match the launch environment because PROMPT is set', async function(done) { + it('updates process.env to match the launch environment because PROMPT is set', async function() { process.env = { WILL_BE_DELETED: 'hi', NODE_ENV: 'the-node-env', @@ -102,11 +100,9 @@ describe('updateProcessEnv(launchEnv)', function() { // case-insensitive environment variable matching, so we cannot replace it // with another object. expect(process.env).toBe(initialProcessEnv); - - done(); }); - it('updates process.env to match the launch environment because PSModulePath is set', async function(done) { + it('updates process.env to match the launch environment because PSModulePath is set', async function() { process.env = { WILL_BE_DELETED: 'hi', NODE_ENV: 'the-node-env', @@ -138,11 +134,9 @@ describe('updateProcessEnv(launchEnv)', function() { // case-insensitive environment variable matching, so we cannot replace it // with another object. expect(process.env).toBe(initialProcessEnv); - - done(); }); - it('allows ATOM_HOME to be overwritten only if the new value is a valid path', async function(done) { + it('allows ATOM_HOME to be overwritten only if the new value is a valid path', async function() { let newAtomHomePath = temp.mkdirSync('atom-home'); process.env = { @@ -189,11 +183,9 @@ describe('updateProcessEnv(launchEnv)', function() { NODE_PATH: '/the/node/path', ATOM_HOME: newAtomHomePath }); - - done(); }); - it('allows ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT to be preserved if set', async function(done) { + it('allows ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT to be preserved if set', async function() { process.env = { WILL_BE_DELETED: 'hi', NODE_ENV: 'the-node-env', @@ -229,11 +221,9 @@ describe('updateProcessEnv(launchEnv)', function() { NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home' }); - - done(); }); - it('allows an existing env variable to be updated', async function(done) { + it('allows an existing env variable to be updated', async function() { process.env = { WILL_BE_UPDATED: 'old-value', NODE_ENV: 'the-node-env', @@ -255,8 +245,6 @@ describe('updateProcessEnv(launchEnv)', function() { await updateProcessEnv(updatedEnv); expect(process.env).toEqual(updatedEnv); - - done(); }); }); @@ -326,21 +314,19 @@ describe('updateProcessEnv(launchEnv)', function() { }); describe('on windows', function() { - it('does not update process.env', async function(done) { + it('does not update process.env', async function() { process.platform = 'win32'; process.env = { FOO: 'bar' }; await updateProcessEnv(process.env); expect(spawn.calls.length).toBe(0); expect(process.env).toEqual({ FOO: 'bar' }); - - done(); }); }); describe('shouldGetEnvFromShell()', function() { - it('indicates when the environment should be fetched from the shell', function() { - jasmine.filterByPlatform({except: ['win32']}); // TestsThatFailOnWin32 + it('indicates when the environment should be fetched from the shell', function(done) { + jasmine.filterByPlatform({except: ['win32']}, done); // TestsThatFailOnWin32 process.platform = 'darwin'; expect(shouldGetEnvFromShell({ SHELL: '/bin/sh' })).toBe(true); @@ -376,6 +362,8 @@ describe('updateProcessEnv(launchEnv)', function() { expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/fish' })).toBe( true ); + + done(); }); it('returns false when the environment indicates that Atom was launched from a shell', function() { diff --git a/spec/uri-handler-registry-spec.js b/spec/uri-handler-registry-spec.js index 100532d1ec..19a8fc3282 100644 --- a/spec/uri-handler-registry-spec.js +++ b/spec/uri-handler-registry-spec.js @@ -11,7 +11,7 @@ describe('URIHandlerRegistry', () => { registry = new URIHandlerRegistry(5); }); - it('handles URIs on a per-host basis', async (done) => { + it('handles URIs on a per-host basis', async () => { const testPackageSpy = jasmine.createSpy(); const otherPackageSpy = jasmine.createSpy(); registry.registerHostHandler('test-package', testPackageSpy); @@ -33,11 +33,9 @@ describe('URIHandlerRegistry', () => { url.parse('atom://other-package/path', true), 'atom://other-package/path' ); - - done(); }); - it('keeps track of the most recent URIs', async (done) => { + it('keeps track of the most recent URIs', async () => { const spy1 = jasmine.createSpy(); const spy2 = jasmine.createSpy(); const changeSpy = jasmine.createSpy(); @@ -77,11 +75,9 @@ describe('URIHandlerRegistry', () => { expect(history.length).toBe(5); expect(history[0].uri).toBe('atom://another/url'); expect(history[4].uri).toBe(uris[1]); - - done(); }); - it('refuses to handle bad URLs', async (done) => { + it('refuses to handle bad URLs', async () => { const invalidUris = [ 'atom:package/path', 'atom:8080://package/path', @@ -100,7 +96,5 @@ describe('URIHandlerRegistry', () => { } expect(numErrors).toBe(invalidUris.length); - - done(); }); }); diff --git a/spec/view-registry-spec.js b/spec/view-registry-spec.js index d4c02f1f51..c5e9b7bf5e 100644 --- a/spec/view-registry-spec.js +++ b/spec/view-registry-spec.js @@ -190,7 +190,7 @@ describe('ViewRegistry', () => { }); describe('::getNextUpdatePromise()', () => - it('returns a promise that resolves at the end of the next update cycle', async (done) => { + it('returns a promise that resolves at the end of the next update cycle', async () => { let updateDocumentSpy = jasmine.createSpy('update document'); let readDocumentSpy = jasmine.createSpy('read document'); @@ -201,7 +201,5 @@ describe('ViewRegistry', () => { expect(updateDocumentSpy).toHaveBeenCalled(); expect(readDocumentSpy).toHaveBeenCalled(); - - done(); })); }); diff --git a/spec/wasm-tree-sitter-language-mode-spec.js b/spec/wasm-tree-sitter-language-mode-spec.js index eeeb1725d7..77846fa9fd 100644 --- a/spec/wasm-tree-sitter-language-mode-spec.js +++ b/spec/wasm-tree-sitter-language-mode-spec.js @@ -63,14 +63,12 @@ function wait(ms) { describe('WASMTreeSitterLanguageMode', () => { let editor, buffer, grammar; - beforeEach(async (done) => { + beforeEach(async () => { grammar = null; editor = await atom.workspace.open(''); buffer = editor.getBuffer(); editor.displayLayer.reset({ foldCharacter: '…' }); atom.config.set('core.useTreeSitterParsers', true); - - done(); }); afterEach(() => { @@ -78,7 +76,7 @@ describe('WASMTreeSitterLanguageMode', () => { }); describe('highlighting', () => { - it('applies the most specific scope mapping to each node in the syntax tree', async (done) => { + it('applies the most specific scope mapping to each node in the syntax tree', async () => { jasmine.useRealClock(); grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -124,11 +122,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: ';', scopes: ['punctuation'] } ] ]); - - done(); }); - it('can start or end multiple scopes at the same position', async (done) => { + it('can start or end multiple scopes at the same position', async () => { jasmine.useRealClock(); grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -175,11 +171,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: ';', scopes: [] } ] ]); - - done(); }); - it('can resume highlighting on a line that starts with whitespace', async (done) => { + it('can resume highlighting on a line that starts with whitespace', async () => { jasmine.useRealClock(); grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -206,11 +200,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: '();', scopes: [] } ] ]); - - done(); }); - it('correctly skips over tokens with zero size', async (done) => { + it('correctly skips over tokens with zero size', async () => { jasmine.useRealClock(); grammar = new WASMTreeSitterGrammar(atom.grammars, cGrammarPath, cConfig); @@ -260,11 +252,9 @@ describe('WASMTreeSitterLanguageMode', () => { ], [{ text: '}', scopes: [] }] ]); - - done(); }); - it("updates lines' highlighting when they are affected by distant changes", async (done) => { + it("updates lines' highlighting when they are affected by distant changes", async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -302,11 +292,9 @@ describe('WASMTreeSitterLanguageMode', () => { [{ text: 'c', scopes: [] }], [{ text: ')', scopes: [] }] ]); - - done(); }); - it('updates the range of the current node in the tree when highlight.invalidateOnChange is set', async (done) => { + it('updates the range of the current node in the tree when highlight.invalidateOnChange is set', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -382,11 +370,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: '`', scopes: ['lorem'] }, ] ]); - - done(); }) - it('handles edits after tokens that end between CR and LF characters (regression)', async (done) => { + it('handles edits after tokens that end between CR and LF characters (regression)', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -430,11 +416,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: 'c', scopes: ['property'] } ] ]); - - done(); }); - it('handles multi-line nodes with children on different lines (regression)', async (done) => { + it('handles multi-line nodes with children on different lines (regression)', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -466,11 +450,9 @@ describe('WASMTreeSitterLanguageMode', () => { ], [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]); - - done(); }); - it('handles folds inside of highlighted tokens', async (done) => { + it('handles folds inside of highlighted tokens', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -506,11 +488,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: '();', scopes: [] } ] ]); - - done(); }); - it('applies regex match rules when specified', async (done) => { + it('applies regex match rules when specified', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -547,11 +527,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: ')', scopes: [] } ] ]); - - done(); }); - it('handles nodes that start before their first child and end after their last child', async (done) => { + it('handles nodes that start before their first child and end after their last child', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, rubyGrammarPath, rubyConfig); @@ -581,14 +559,12 @@ describe('WASMTreeSitterLanguageMode', () => { { text: ' )', scopes: [] } ] ]); - - done(); }); // TODO: Ignoring these specs because web-tree-sitter doesn't seem to do // async. We can rehabilitate them if we ever figure it out. xdescribe('when the buffer changes during a parse', () => { - it('immediately parses again when the current parse completes', async (done) => { + it('immediately parses again when the current parse completes', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -659,13 +635,11 @@ describe('WASMTreeSitterLanguageMode', () => { await languageMode.atTransactionEnd(); // await wait(2000); - - done(); }); }); describe('when changes are small enough to be re-parsed synchronously', () => { - it('can incorporate multiple consecutive synchronous updates', async (done) => { + it('can incorporate multiple consecutive synchronous updates', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -719,15 +693,13 @@ describe('WASMTreeSitterLanguageMode', () => { expectTokensToEqual(editor, [ [{ text: 'ab', scopes: ['function'] }, { text: '()', scopes: [] }] ]); - - done(); }); }); describe('injectionPoints and injectionPatterns', () => { let jsGrammar, htmlGrammar; - beforeEach(async (done) => { + beforeEach(async () => { let tempJsConfig = { ...jsConfig }; jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, tempJsConfig); @@ -753,11 +725,9 @@ describe('WASMTreeSitterLanguageMode', () => { `); htmlGrammar.addInjectionPoint(SCRIPT_TAG_INJECTION_POINT); - - done(); }); - it('highlights code inside of injection points', async (done) => { + it('highlights code inside of injection points', async () => { jasmine.useRealClock(); atom.grammars.addGrammar(jsGrammar); atom.grammars.addGrammar(htmlGrammar); @@ -821,11 +791,9 @@ describe('WASMTreeSitterLanguageMode', () => { ], [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]); - - done(); }); - it('highlights the content after injections', async (done) => { + it('highlights the content after injections', async () => { jasmine.useRealClock(); atom.grammars.addGrammar(jsGrammar); atom.grammars.addGrammar(htmlGrammar); @@ -866,11 +834,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: '>', scopes: ['html'] } ] ]); - - done(); }); - it('updates a buffer\'s highlighting when a grammar with injectionRegex is added', async (done) => { + it('updates a buffer\'s highlighting when a grammar with injectionRegex is added', async () => { jasmine.useRealClock(); atom.grammars.addGrammar(jsGrammar); @@ -930,11 +896,9 @@ describe('WASMTreeSitterLanguageMode', () => { ], [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]); - - done(); }); - it('handles injections that intersect', async (done) => { + it('handles injections that intersect', async () => { const ejsGrammar = new WASMTreeSitterGrammar( atom.grammars, @@ -1003,11 +967,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: '>', scopes: ['html'] } ] ]); - - done(); }); - it('handles injections that are empty', async (done) => { + it('handles injections that are empty', async () => { jasmine.useRealClock(); atom.grammars.addGrammar(jsGrammar); atom.grammars.addGrammar(htmlGrammar); @@ -1067,11 +1029,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: ';', scopes: [] } ] ]); - - done(); }); - it('handles injections with no highlights query', async (done) => { + it('handles injections with no highlights query', async () => { jasmine.useRealClock(); atom.grammars.addGrammar(jsGrammar); atom.grammars.addGrammar(htmlGrammar); @@ -1095,11 +1055,9 @@ describe('WASMTreeSitterLanguageMode', () => { let descriptor = editor.scopeDescriptorForBufferPosition([0, 15]); expect(descriptor.getScopesArray()).toContain('text.html.basic'); - - done(); }); - it('terminates comment token at the end of an injection, so that the next injection is NOT a continuation of the comment', async (done) => { + it('terminates comment token at the end of an injection, so that the next injection is NOT a continuation of the comment', async () => { jasmine.useRealClock(); const ejsGrammar = new WASMTreeSitterGrammar( atom.grammars, @@ -1154,11 +1112,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: '%>', scopes: ['directive'] } ] ]); - - done(); }); - it('only covers scope boundaries in parent layers if a nested layer has a boundary at the same position', async (done) => { + it('only covers scope boundaries in parent layers if a nested layer has a boundary at the same position', async () => { const jsdocGrammar = new WASMTreeSitterGrammar( atom.grammars, jsdocGrammarPath, @@ -1188,11 +1144,9 @@ describe('WASMTreeSitterLanguageMode', () => { [{ text: '{', scopes: [] }], [{ text: '}', scopes: [] }] ]); - - done(); }); - it('reports scopes from shallower layers when they are at the start or end of an injection', async (done) => { + it('reports scopes from shallower layers when they are at the start or end of an injection', async () => { jasmine.useRealClock(); await atom.packages.activatePackage('language-javascript'); @@ -1246,11 +1200,9 @@ describe('WASMTreeSitterLanguageMode', () => { } ] ]); - - done(); }); - it('respects the `includeChildren` property of injection points', async (done) => { + it('respects the `includeChildren` property of injection points', async () => { const rustGrammar = new WASMTreeSitterGrammar( atom.grammars, rustGrammarPath, @@ -1327,11 +1279,9 @@ describe('WASMTreeSitterLanguageMode', () => { { text: '();', scopes: [] } ] ]); - - done(); }); - it('omits the injected grammar\'s base scope when `languageScope` is `null`', async (done) => { + it('omits the injected grammar\'s base scope when `languageScope` is `null`', async () => { let customJsConfig = { ...jsConfig }; let customJsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, customJsConfig); @@ -1377,11 +1327,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( descriptor.getScopesArray().includes('source.js') ).toBe(false); - - done(); }); - it('uses a custom base scope on the injected layer when `languageScope` is a string', async (done) => { + it('uses a custom base scope on the injected layer when `languageScope` is a string', async () => { let customJsConfig = { ...jsConfig }; let customJsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, customJsConfig); @@ -1430,11 +1378,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( descriptor.getScopesArray().includes('source.js.embedded') ).toBe(true); - - done(); }); - it('uses a custom base scope on the injected layer when `languageScope` is a function', async (done) => { + it('uses a custom base scope on the injected layer when `languageScope` is a function', async () => { let customJsConfig = { ...jsConfig }; let customJsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, customJsConfig); @@ -1485,11 +1431,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( descriptor.getScopesArray().includes(`source.js.custom-${timestamp}`) ).toBe(true); - - done(); }); - it('allows multiple base scopes on the injected layer when `languageScope` is a function', async (done) => { + it('allows multiple base scopes on the injected layer when `languageScope` is a function', async () => { let customJsConfig = { ...jsConfig }; let customJsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, customJsConfig); @@ -1554,11 +1498,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( descriptor.getScopesArray().includes(`meta.line0`) ).toBe(false); - - done(); }); - it('notifies onDidTokenize listeners the first time all syntax highlighting is done', async (done) => { + it('notifies onDidTokenize listeners the first time all syntax highlighting is done', async () => { const promise = new Promise(resolve => { editor.onDidTokenize(event => { expectTokensToEqual(editor, [ @@ -1593,8 +1535,6 @@ describe('WASMTreeSitterLanguageMode', () => { }); buffer.setLanguageMode(languageMode); await promise; - - done(); }); }); }); @@ -1611,7 +1551,7 @@ describe('WASMTreeSitterLanguageMode', () => { jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; }); - it('matches the highlighting of a freshly-opened editor', async (done) => { + it('matches the highlighting of a freshly-opened editor', async () => { jasmine.useRealClock(); const text = fs.readFileSync( @@ -1695,8 +1635,6 @@ describe('WASMTreeSitterLanguageMode', () => { expect(tokens1).toEqual(tokens2, `Seed: ${seed}, screen line: ${j}`); } } - - done(); }); }); @@ -1704,12 +1642,10 @@ describe('WASMTreeSitterLanguageMode', () => { let editor; describe('javascript', () => { - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('sample.js', { autoIndent: false }); await atom.packages.activatePackage('language-javascript'); await editor.getBuffer().getLanguageMode().ready; - - done(); }); it('bases indentation off of the previous non-blank line', () => { @@ -1735,16 +1671,14 @@ describe('WASMTreeSitterLanguageMode', () => { }); describe('css', () => { - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('css.css', { autoIndent: true }); await atom.packages.activatePackage('language-source'); await atom.packages.activatePackage('language-css'); await editor.getBuffer().getLanguageMode().ready; - - done(); }); - it('does not return negative values (regression)', async (done) => { + it('does not return negative values (regression)', async () => { jasmine.useRealClock(); editor.setText('.test {\npadding: 0;\n}'); await wait(0); @@ -1753,20 +1687,16 @@ describe('WASMTreeSitterLanguageMode', () => { editor.setText('@media screen {\n .test {\n padding: 0;\n }\n}'); await wait(0); expect(editor.suggestedIndentForBufferRow(3)).toBe(1); - - done(); }); }); }); describe('.suggestedIndentForBufferRows', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('language-javascript'); - - done(); }) - it('works correctly when straddling an injection boundary', async (done) => { + it('works correctly when straddling an injection boundary', async () => { const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -1811,13 +1741,11 @@ describe('WASMTreeSitterLanguageMode', () => { let map = languageMode.suggestedIndentForBufferRows(0, 5, editor.getTabLength()); expect(Array.from(map.values())).toEqual([0, 1, 1, 2, 1, 0]); - - done(); }); }); describe('folding', () => { - it('can fold nodes that start and end with specified tokens', async (done) => { + it('can fold nodes that start and end with specified tokens', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('foldsQuery', ` @@ -1869,11 +1797,9 @@ describe('WASMTreeSitterLanguageMode', () => { getB (c,…) {…} } `); - - done(); }); - it('folds entire buffer rows when necessary to keep words on separate lines', async (done) => { + it('folds entire buffer rows when necessary to keep words on separate lines', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('foldsQuery', ` @@ -1932,11 +1858,9 @@ describe('WASMTreeSitterLanguageMode', () => { } else if (c) {… } else {…} `); - - done(); }); - it('can fold nodes of specified types', async (done) => { + it('can fold nodes of specified types', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('foldsQuery', ` @@ -1993,11 +1917,9 @@ describe('WASMTreeSitterLanguageMode', () => { const element2 = `); - - done(); }); - it('updates its fold cache properly when `fold.invalidateOnChange` is specified', async (done) => { + it('updates its fold cache properly when `fold.invalidateOnChange` is specified', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, htmlGrammarPath, htmlConfig); await grammar.setQueryForTest('foldsQuery', scm` @@ -2061,11 +1983,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(2)).toBe(true); expect(editor.isFoldableAtBufferRow(3)).toBe(false); expect(editor.isFoldableAtBufferRow(4)).toBe(false); - - done(); }); - it('understands custom predicates', async (done) => { + it('understands custom predicates', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, htmlGrammarPath, htmlConfig); await grammar.setQueryForTest('foldsQuery', scm` @@ -2109,11 +2029,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(0)).toBe(false); expect(editor.isFoldableAtBufferRow(7)).toBe(true); - - done(); }); - it('can fold entire nodes when no start or end parameters are specified', async (done) => { + it('can fold entire nodes when no start or end parameters are specified', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('foldsQuery', ` @@ -2154,11 +2072,9 @@ describe('WASMTreeSitterLanguageMode', () => { /**… */ const x = 1 /*…*/ `); - - done(); }); - it('folds between arbitrary points in the buffer with @fold.start and @fold.end markers', async (done) => { + it('folds between arbitrary points in the buffer with @fold.start and @fold.end markers', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, cGrammarPath, cConfig); await grammar.setQueryForTest('foldsQuery', ` @@ -2254,11 +2170,9 @@ describe('WASMTreeSitterLanguageMode', () => { #endif `); - - done(); }); - it('does not fold when the start and end parameters match the same child', async (done) => { + it('does not fold when the start and end parameters match the same child', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, htmlGrammarPath, htmlConfig); await grammar.setQueryForTest('foldsQuery', ` @@ -2284,11 +2198,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect(getDisplayText(editor)).toBe(dedent` … `); - - done(); }); - it('can target named vs anonymous nodes as fold boundaries', async (done) => { + it('can target named vs anonymous nodes as fold boundaries', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, rubyGrammarPath, rubyConfig); await grammar.setQueryForTest('foldsQuery', ` @@ -2349,11 +2261,9 @@ describe('WASMTreeSitterLanguageMode', () => { else… end `); - - done(); }); - it('updates fold locations when the buffer changes', async (done) => { + it('updates fold locations when the buffer changes', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('foldsQuery', ` @@ -2393,12 +2303,10 @@ describe('WASMTreeSitterLanguageMode', () => { expect(languageMode.isFoldableAtRow(2)).toBe(false); expect(languageMode.isFoldableAtRow(3)).toBe(true); expect(languageMode.isFoldableAtRow(4)).toBe(false); - - done(); }); describe('when folding a node that ends with a line break', () => { - it('ends the fold at the end of the previous line', async (done) => { + it('ends the fold at the end of the previous line', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, pythonGrammarPath, CSON.readFileSync(pythonGrammarPath) @@ -2462,12 +2370,10 @@ describe('WASMTreeSitterLanguageMode', () => { print 'c' print 'd' `); - - done(); }); }); - it('folds code in injected languages', async (done) => { + it('folds code in injected languages', async () => { jasmine.useRealClock(); const htmlGrammar = new WASMTreeSitterGrammar( atom.grammars, @@ -2538,13 +2444,11 @@ describe('WASMTreeSitterLanguageMode', () => { `a = html \`…\` ` ); - - done(); }); }); describe('.scopeDescriptorForPosition', () => { - it('returns a scope descriptor representing the given position in the syntax tree', async (done) => { + it('returns a scope descriptor representing the given position in the syntax tree', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('highlightsQuery', ` @@ -2587,11 +2491,9 @@ describe('WASMTreeSitterLanguageMode', () => { .scopeDescriptorForBufferPosition([0, '// baz'.length]) .getScopesArray() ).toEqual(['source.js', 'comment.block']); - - done(); }); - it('includes nodes in injected syntax trees', async (done) => { + it('includes nodes in injected syntax trees', async () => { const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await jsGrammar.setQueryForTest('highlightsQuery', ` @@ -2646,11 +2548,9 @@ describe('WASMTreeSitterLanguageMode', () => { 'string.quoted', 'property.name' ]); - - done(); }); - it('reports scopes correctly at boundaries where more than one layer adds a scope', async (done) => { + it('reports scopes correctly at boundaries where more than one layer adds a scope', async () => { const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await jsGrammar.setQueryForTest('highlightsQuery', ` @@ -2703,11 +2603,9 @@ describe('WASMTreeSitterLanguageMode', () => { 'text.html.basic', 'tag' ]); - - done(); }); - it('includes the root scope name even when the given position is in trailing whitespace at EOF', async (done) => { + it('includes the root scope name even when the given position is in trailing whitespace at EOF', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('highlightsQuery', ` @@ -2723,11 +2621,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray() ).toEqual(['source.js']); - - done(); }); - it('works when the given position is between tokens', async (done) => { + it('works when the given position is between tokens', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('highlightsQuery', ` @@ -2746,11 +2642,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray() ).toEqual(['source.js', 'comment.block']); - - done(); }); - it('works when a scope range has been adjusted', async (done) => { + it('works when a scope range has been adjusted', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('highlightsQuery', ` @@ -2774,11 +2668,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( editor.scopeDescriptorForBufferPosition([1, 2]).getScopesArray() ).toEqual(['source.js', 'comment.block']); - - done(); }); - it('ignores a parent\'s scopes if an injection layer sets `coverShallowerScopes`', async (done) => { + it('ignores a parent\'s scopes if an injection layer sets `coverShallowerScopes`', async () => { jasmine.useRealClock(); const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -2840,11 +2732,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect(scopes.includes('gadfly')).toBe(false); expect(scopes.includes('regex-outer')).toBe(true); expect(scopes.includes('regex-inner')).toBe(false); - - done(); }); - it('arranges scopes in the proper order when scopes from several layers were already open at a given point', async (done) => { + it('arranges scopes in the proper order when scopes from several layers were already open at a given point', async () => { jasmine.useRealClock(); const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -2908,14 +2798,12 @@ describe('WASMTreeSitterLanguageMode', () => { "string.regexp", "gadfly" ]); - - done(); }); }); describe('.syntaxTreeScopeDescriptorForPosition', () => { - it('returns a scope descriptor representing the given position in the syntax tree', async (done) => { + it('returns a scope descriptor representing the given position in the syntax tree', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -2951,11 +2839,9 @@ describe('WASMTreeSitterLanguageMode', () => { .syntaxTreeScopeDescriptorForBufferPosition([0, 5]) .getScopesArray() ).toEqual(['source.js', 'program', 'comment']); - - done(); }); - it('includes nodes in injected syntax trees', async (done) => { + it('includes nodes in injected syntax trees', async () => { const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); jsGrammar.addInjectionPoint(HTML_TEMPLATE_LITERAL_INJECTION_POINT); @@ -3011,14 +2897,12 @@ describe('WASMTreeSitterLanguageMode', () => { 'member_expression', 'property_identifier' ]); - - done(); }); }); describe('.bufferRangeForScopeAtPosition(selector?, position)', () => { describe('when selector = null', () => { - it('returns the range of the smallest node at position', async (done) => { + it('returns the range of the smallest node at position', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); buffer.setText('foo({bar: baz});'); @@ -3035,11 +2919,9 @@ describe('WASMTreeSitterLanguageMode', () => { [0, 8], [0, 9] ]); - - done(); }); - it('includes nodes in injected syntax trees', async (done) => { + it('includes nodes in injected syntax trees', async () => { const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); jsGrammar.addInjectionPoint(HTML_TEMPLATE_LITERAL_INJECTION_POINT); @@ -3087,13 +2969,11 @@ describe('WASMTreeSitterLanguageMode', () => { expect( languageMode.bufferRangeForScopeAtPosition(null, position) ).toEqual(nameProperty); - - done(); }); }); describe('with a selector', () => { - it('returns the range of the smallest matching node at position', async (done) => { + it('returns the range of the smallest matching node at position', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('highlightsQuery', ` @@ -3113,11 +2993,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( editor.bufferRangeForScopeAtPosition('.string.quoted', [0, 6]) ).toEqual([[0, 2], [0, 24]]); - - done(); }); - it('includes nodes in injected syntax trees', async (done) => { + it('includes nodes in injected syntax trees', async () => { const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); jsGrammar.addInjectionPoint(HTML_TEMPLATE_LITERAL_INJECTION_POINT); await jsGrammar.setQueryForTest('highlightsQuery', ` @@ -3172,11 +3050,9 @@ describe('WASMTreeSitterLanguageMode', () => { position ) ).toEqual(buffer.findSync('\\${person\\.name}')); - - done(); }); - it('reports results correctly when scope ranges have been adjusted', async (done) => { + it('reports results correctly when scope ranges have been adjusted', async () => { jasmine.useRealClock(); const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -3213,11 +3089,9 @@ describe('WASMTreeSitterLanguageMode', () => { range = languageMode.bufferRangeForScopeAtPosition('comment.block', new Point(1, 0)); expect(range.toString()).toBe(`[(1, 0) - (1, 29)]`); - - done(); }); - it('ignores scopes that are not present because they are covered by a deeper layer', async (done) => { + it('ignores scopes that are not present because they are covered by a deeper layer', async () => { // A similar test to the one above, except now we expect not to see the // scope because it's being covered by the injection layer. jasmine.useRealClock(); @@ -3273,11 +3147,9 @@ describe('WASMTreeSitterLanguageMode', () => { let point = new Point(0, 15); let range = languageMode.bufferRangeForScopeAtPosition('keyword', point); expect(range).toBe(undefined); - - done(); }); - it('accepts node-matching functions as selectors', async (done) => { + it('accepts node-matching functions as selectors', async () => { const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); jsGrammar.addInjectionPoint(HTML_TEMPLATE_LITERAL_INJECTION_POINT); @@ -3327,14 +3199,12 @@ describe('WASMTreeSitterLanguageMode', () => { position ) ).toEqual([[3, 19], [5, 15]]); - - done(); }); }); }); describe('.getSyntaxNodeAtPosition(position, where?)', () => { - it('returns the range of the smallest matching node at position', async (done) => { + it('returns the range of the smallest matching node at position', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); buffer.setText('foo(bar({x: 2}));'); @@ -3356,8 +3226,6 @@ describe('WASMTreeSitterLanguageMode', () => { expect( languageMode.getSyntaxNodeAtPosition([0, 6], findFoo).range ).toEqual([[0, 0], [0, buffer.getText().length - 1]]); - - done(); }); }); @@ -3371,7 +3239,7 @@ describe('WASMTreeSitterLanguageMode', () => { atom.config.unset('editor.commentEnd', { scopeSelector: '.text.html.basic' }); }); - it('returns the correct comment strings for nested languages', async (done) => { + it('returns the correct comment strings for nested languages', async () => { jasmine.useRealClock(); const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -3495,11 +3363,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect(languageMode.commentStringsForPosition(new Point(6, 0))).toEqual( htmlCommentStrings ); - - done(); }); - it('uses grammar comment settings when config data is missing', async (done) => { + it('uses grammar comment settings when config data is missing', async () => { jasmine.useRealClock(); const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -3587,11 +3453,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect(languageMode.commentStringsForPosition(new Point(6, 0))).toEqual( htmlCommentStrings ); - - done(); }); - it('constructs the right comment settings when grammar data is missing', async (done) => { + it('constructs the right comment settings when grammar data is missing', async () => { jasmine.useRealClock(); const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -3699,14 +3563,12 @@ describe('WASMTreeSitterLanguageMode', () => { expect(languageMode.commentStringsForPosition(new Point(6, 0))).toEqual( htmlCommentStrings ); - - done(); }); }); describe('TextEditor.selectLargerSyntaxNode and .selectSmallerSyntaxNode', () => { - it('expands and contracts the selection based on the syntax tree', async (done) => { + it('expands and contracts the selection based on the syntax tree', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('highlightsQuery', ` @@ -3748,11 +3610,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect(editor.getSelectedText()).toBe('eee'); editor.selectSmallerSyntaxNode(); expect(editor.getSelectedBufferRange()).toEqual([[1, 3], [1, 3]]); - - done(); }); - it('handles injected languages', async (done) => { + it('handles injected languages', async () => { const jsGrammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await jsGrammar.setQueryForTest('highlightsQuery', ` @@ -3808,13 +3668,11 @@ describe('WASMTreeSitterLanguageMode', () => { expect(editor.getSelectedText()).toBe('` c${def()}e${f}g `'); editor.selectLargerSyntaxNode(); expect(editor.getSelectedText()).toBe('html ` c${def()}e${f}g `'); - - done(); }); }); describe('.tokenizedLineForRow(row)', () => { - it('returns a shimmed TokenizedLine with tokens', async (done) => { + it('returns a shimmed TokenizedLine with tokens', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); await grammar.setQueryForTest('highlightsQuery', ` @@ -3871,20 +3729,16 @@ describe('WASMTreeSitterLanguageMode', () => { { value: ' ', scopes: ['source'] }, { value: 'b', scopes: ['source', 'variable'] } ]); - - done(); }); }); describe('indentation', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.packages.activatePackage('whitespace'); atom.config.set('whitespace.removeTrailingWhitespace', false); - - done(); }); - it('interprets @indent and @dedent captures', async (done) => { + it('interprets @indent and @dedent captures', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -3925,11 +3779,9 @@ describe('WASMTreeSitterLanguageMode', () => { editor.undo(); expect(buffer.getText()).toEqual(originalText); - - done(); }); - it('allows @dedents to cancel out @indents when appropriate', async (done) => { + it('allows @dedents to cancel out @indents when appropriate', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -3962,11 +3814,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( editor.getLastCursor().getBufferPosition().toString() ).toEqual('(1, 2)'); - - done(); }); - it('allows @dedent.next to decrease the indent of the next line before any typing takes place', async (done) => { + it('allows @dedent.next to decrease the indent of the next line before any typing takes place', async () => { const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); // Pretend we're in a universe where lines after comments should be @@ -3986,11 +3836,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( editor.getLastCursor().getBufferPosition().toString() ).toEqual('(1, 0)'); - - done(); }); - it('resolves @match captures', async (done) => { + it('resolves @match captures', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4024,11 +3872,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( editor.getLastCursor().getBufferPosition().toString() ).toEqual('(2, 1)'); - - done(); }); - it('prefers a @match capture even if a @dedent matches first', async (done) => { + it('prefers a @match capture even if a @dedent matches first', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4062,11 +3908,9 @@ describe('WASMTreeSitterLanguageMode', () => { expect( editor.getLastCursor().getBufferPosition().toString() ).toEqual('(2, 1)'); - - done(); }); - it('adjusts correctly when text is pasted', async (done) => { + it('adjusts correctly when text is pasted', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4120,11 +3964,9 @@ describe('WASMTreeSitterLanguageMode', () => { await wait(0); expect(editor.getText()).toEqual(emptyClassText); - - done(); }); - it('skips trying to insert at the correct indentation level when "paste without formatting" is invoked', async (done) => { + it('skips trying to insert at the correct indentation level when "paste without formatting" is invoked', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4178,12 +4020,10 @@ describe('WASMTreeSitterLanguageMode', () => { await wait(0); expect(editor.getText()).toEqual(emptyClassText); - - done(); }); - it('preserves relative indentation across pasted text', async (done) => { + it('preserves relative indentation across pasted text', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4235,11 +4075,9 @@ describe('WASMTreeSitterLanguageMode', () => { await wait(0); expect(editor.getText()).toEqual(emptyClassText); - - done(); }); - it('preserves relative indentation across pasted text (when the pasted text ends in a newline)', async (done) => { + it('preserves relative indentation across pasted text (when the pasted text ends in a newline)', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4290,11 +4128,9 @@ describe('WASMTreeSitterLanguageMode', () => { await wait(0); expect(editor.getText()).toEqual(emptyClassText); - - done(); }); - it('auto-indents correctly if any change in a transaction wants auto-indentation', async (done) => { + it('auto-indents correctly if any change in a transaction wants auto-indentation', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); editor.updateAutoIndent(true); @@ -4370,11 +4206,9 @@ describe('WASMTreeSitterLanguageMode', () => { await wait(0); expect(editor.getText()).toEqual(emptyClassText); - - done(); }); - it('does not auto-indent if no change in a transaction wants auto-indentation', async (done) => { + it('does not auto-indent if no change in a transaction wants auto-indentation', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4421,11 +4255,9 @@ describe('WASMTreeSitterLanguageMode', () => { await wait(0); expect(editor.getText()).toEqual(emptyClassText); - - done(); }); - it('auto-dedents exactly once and not after each new insertion on a line', async (done) => { + it('auto-dedents exactly once and not after each new insertion on a line', async () => { jasmine.useRealClock(); editor.updateAutoIndent(true); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4460,11 +4292,9 @@ describe('WASMTreeSitterLanguageMode', () => { editor.insertText(' ', { autoIndent: true }); await languageMode.atTransactionEnd(); expect(editor.lineTextForBufferRow(2)).toEqual(` } `); - - done(); }); - it('maintains indent level through multiple newlines (removeTrailingWhitespace: true)', async (done) => { + it('maintains indent level through multiple newlines (removeTrailingWhitespace: true)', async () => { jasmine.useRealClock(); editor.updateAutoIndent(true); atom.config.set('whitespace.removeTrailingWhitespace', true); @@ -4508,11 +4338,9 @@ describe('WASMTreeSitterLanguageMode', () => { await languageMode.atTransactionEnd(); await wait(0); expect(editor.lineTextForBufferRow(4)).toEqual(' '); - - done(); }); - it('does not attempt to adjust indent on pasted text without a newline', async (done) => { + it('does not attempt to adjust indent on pasted text without a newline', async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4556,11 +4384,9 @@ describe('WASMTreeSitterLanguageMode', () => { await wait(0); expect(editor.getText()).toEqual(emptyClassText); - - done(); }); - it('maintains indent level through multiple newlines (removeTrailingWhitespace: false)', async (done) => { + it('maintains indent level through multiple newlines (removeTrailingWhitespace: false)', async () => { jasmine.useRealClock(); editor.updateAutoIndent(true); atom.config.set('whitespace.removeTrailingWhitespace', false); @@ -4604,11 +4430,9 @@ describe('WASMTreeSitterLanguageMode', () => { await languageMode.atTransactionEnd(); await wait(0); expect(editor.lineTextForBufferRow(4)).toEqual(' '); - - done(); }); - it(`can indent properly in a multi-cursor environment without auto-indenting large ranges of the buffer`, async (done) => { + it(`can indent properly in a multi-cursor environment without auto-indenting large ranges of the buffer`, async () => { jasmine.useRealClock(); const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig); @@ -4663,8 +4487,6 @@ describe('WASMTreeSitterLanguageMode', () => { function test () { return } `) - - done(); }) }); diff --git a/spec/window-event-handler-spec.js b/spec/window-event-handler-spec.js index a9f58e49a0..ba454d2023 100644 --- a/spec/window-event-handler-spec.js +++ b/spec/window-event-handler-spec.js @@ -28,9 +28,11 @@ describe('WindowEventHandler', () => { }); describe('when the window is loaded', () => - it("doesn't have .is-blurred on the body tag", () => { - jasmine.filterByPlatform({except: ['win32']}); // Win32TestFailures - can not steal focus + it("doesn't have .is-blurred on the body tag", (done) => { + jasmine.filterByPlatform({except: ['win32']}, done); // Win32TestFailures - can not steal focus expect(document.body.className).not.toMatch('is-blurred'); + + done(); })); describe('when the window is blurred', () => { diff --git a/spec/workspace-element-spec.js b/spec/workspace-element-spec.js index 74be948bba..d99745f15d 100644 --- a/spec/workspace-element-spec.js +++ b/spec/workspace-element-spec.js @@ -665,7 +665,7 @@ describe('WorkspaceElement', () => { ); }); - it('shows the toggle button when the dock is open', async (done) => { + it('shows the toggle button when the dock is open', async () => { await Promise.all([ atom.workspace.open({ element: document.createElement('div'), @@ -835,8 +835,6 @@ describe('WorkspaceElement', () => { await getNextUpdatePromise(); expect(bottomDock.isVisible()).toBe(true); expectToggleButtonVisible(bottomDock, 'icon-chevron-down'); - - done(); }); function moveMouse(coordinates) { @@ -885,18 +883,16 @@ describe('WorkspaceElement', () => { describe('editor font styling', () => { let editor, editorElement, workspaceElement; - beforeEach(async (done) => { + beforeEach(async () => { await atom.workspace.open('sample.js'); workspaceElement = atom.workspace.getElement(); jasmine.attachToDOM(workspaceElement); editor = atom.workspace.getActiveTextEditor(); editorElement = editor.getElement(); - - done(); }); - it("updates the font-size based on the 'editor.fontSize' config value", async (done) => { + 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' @@ -915,11 +911,9 @@ describe('WorkspaceElement', () => { atom.config.get('editor.fontSize') + 'px' ); expect(editor.getDefaultCharWidth()).toBeGreaterThan(initialCharWidth); - - done(); }); - it("updates the font-family based on the 'editor.fontFamily' config value", async (done) => { + it("updates the font-family based on the 'editor.fontFamily' config value", async () => { const initialCharWidth = editor.getDefaultCharWidth(); let fontFamily = atom.config.get('editor.fontFamily'); expect(getComputedStyle(editorElement).fontFamily).toBe(fontFamily); @@ -932,11 +926,9 @@ describe('WorkspaceElement', () => { fontFamily = atom.config.get('editor.fontFamily'); expect(getComputedStyle(editorElement).fontFamily).toBe(fontFamily); expect(editor.getDefaultCharWidth()).not.toBe(initialCharWidth); - - done(); }); - it("updates the line-height based on the 'editor.lineHeight' config value", async (done) => { + it("updates the line-height based on the 'editor.lineHeight' config value", async () => { const initialLineHeight = editor.getLineHeightInPixels(); await new Promise((resolve) => { @@ -948,8 +940,6 @@ describe('WorkspaceElement', () => { atom.config.get('editor.lineHeight') ); expect(editor.getLineHeightInPixels()).not.toBe(initialLineHeight); - - done(); }); it('increases or decreases the font size when a ctrl-mousewheel event occurs', () => { diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index 3a5d9dc8e2..1850aa7f92 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -19,7 +19,7 @@ describe('Workspace', () => { let fsGetSizeSyncSpy; let fsOpenSyncSpy; - beforeEach(async (done) => { + beforeEach(async () => { fsGetSizeSyncSpy ||= spyOn(fs, 'getSizeSync').and.callThrough(); fsOpenSyncSpy ||= spyOn(fs, 'openSync').and.callThrough(); @@ -33,8 +33,6 @@ describe('Workspace', () => { atom.project.setPaths([atom.project.getDirectories()[0].resolve('dir')]); await atom.workspace.itemLocationStore.clear(); - - done(); }); afterEach(() => { @@ -81,7 +79,7 @@ describe('Workspace', () => { describe('serialization', () => { describe('when the workspace contains text editors', () => { - it('constructs the view with the same panes', async (done) => { + it('constructs the view with the same panes', async () => { const pane1 = atom.workspace.getActivePane(); const pane2 = pane1.splitRight({ copyActiveItem: true }); const pane3 = pane2.splitRight({ copyActiveItem: true }); @@ -138,20 +136,16 @@ describe('Workspace', () => { `^${path.basename(editor3.getLongTitle())} \\u2014 ${pathEscaped}` ) ); - - done(); }); }); describe('where there are no open panes or editors', () => { - it('constructs the view with no open editors', async (done) => { + it('constructs the view with no open editors', async () => { atom.workspace.getActivePane().destroy(); expect(atom.workspace.getTextEditors().length).toBe(0); await simulateReload(); expect(atom.workspace.getTextEditors().length).toBe(0); - - done(); }); }); }); @@ -167,7 +161,7 @@ describe('Workspace', () => { describe("when the 'searchAllPanes' option is false (default)", () => { describe('when called without a uri or item', () => { - it('adds and activates an empty editor on the active pane', async (done) => { + it('adds and activates an empty editor on the active pane', async () => { let editor1; let editor2; @@ -201,14 +195,12 @@ describe('Workspace', () => { index: 1 } ]); - - done(); }); }); describe('when called with a uri', () => { describe('when the active pane already has an editor for the given uri', () => { - it('activates the existing editor on the active pane', async (done) => { + it('activates the existing editor on the active pane', async () => { let editor = null; let editor1 = null; let editor2 = null; @@ -242,11 +234,9 @@ describe('Workspace', () => { index: 0 } ]); - - done(); }); - it('finds items in docks', async (done) => { + it('finds items in docks', async () => { const dock = atom.workspace.getRightDock(); const ITEM_URI = 'atom://test'; const item = { @@ -262,13 +252,11 @@ describe('Workspace', () => { expect(atom.workspace.getPaneItems()).toHaveLength(1); expect(dock.getPaneItems()).toHaveLength(1); expect(dock.getPaneItems()[0]).toBe(item); - - done(); }); }); describe("when the 'activateItem' option is false", () => { - it('adds the item to the workspace', async (done) => { + it('adds the item to the workspace', async () => { let editor; await workspace.open('a'); @@ -276,8 +264,6 @@ describe('Workspace', () => { expect(workspace.getPaneItems()).toContain(editor); expect(workspace.getActivePaneItem()).not.toBe(editor); - - done(); }); }); @@ -286,14 +272,12 @@ describe('Workspace', () => { atom.workspace.enablePersistence = true; }); - afterEach(async (done) => { + afterEach(async () => { await atom.workspace.itemLocationStore.clear(); atom.workspace.enablePersistence = false; - - done(); }); - it('adds and activates a new editor for the given path on the active pane', async (done) => { + it('adds and activates a new editor for the given path on the active pane', async () => { let editor = await workspace.open('a'); const firstDirectory = atom.project.getDirectories()[0]; @@ -302,11 +286,9 @@ describe('Workspace', () => { expect(workspace.getActivePaneItem()).toBe(editor); expect(workspace.getActivePane().items).toEqual([editor]); expect(workspace.getActivePane().activate).toHaveBeenCalled(); - - done(); }); - it('discovers existing editors that are still opening', async (done) => { + it('discovers existing editors that are still opening', async () => { let editor0 = null; let editor1 = null; @@ -321,11 +303,9 @@ describe('Workspace', () => { expect(editor0).toEqual(editor1); expect(workspace.getActivePane().items).toEqual([editor0]); - - done(); }); - it("uses the location specified by the model's `getDefaultLocation()` method", async (done) => { + it("uses the location specified by the model's `getDefaultLocation()` method", async () => { const item = { getDefaultLocation: jasmine.createSpy().and.returnValue('right'), getElement: () => document.createElement('div') @@ -343,11 +323,9 @@ describe('Workspace', () => { expect(dock.getPaneItems()).toHaveLength(1); expect(opener).toHaveBeenCalled(); expect(item.getDefaultLocation).toHaveBeenCalled(); - - done(); }); - it('prefers the last location the user used for that item', async (done) => { + it('prefers the last location the user used for that item', async () => { const ITEM_URI = 'atom://test'; const item = { getURI: () => ITEM_URI, @@ -368,14 +346,12 @@ describe('Workspace', () => { expect(dock.getPaneItems()).toHaveLength(1); expect(dock.getPaneItems()[0]).toBe(item); - - done(); }); }); }); 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 (done) => { + 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( @@ -396,15 +372,13 @@ describe('Workspace', () => { 'center' ); expect(atom.workspace.getPaneItems()).toEqual([item, item2]); - - done(); }); }); }); describe("when the 'searchAllPanes' option is true", () => { describe('when an editor for the given uri is already open on an inactive pane', () => { - it('activates the existing editor on the inactive pane, then activates that pane', async (done) => { + it('activates the existing editor on the inactive pane, then activates that pane', async () => { let editor1 = null; let editor2 = null; const pane1 = workspace.getActivePane(); @@ -422,11 +396,9 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane1); expect(workspace.getActivePaneItem()).toBe(editor1); - - done(); }); - it('discovers existing editors that are still opening in an inactive pane', async (done) => { + it('discovers existing editors that are still opening in an inactive pane', async () => { let editor0 = null; let editor1 = null; const pane0 = workspace.getActivePane(); @@ -452,11 +424,9 @@ describe('Workspace', () => { expect(editor0).toEqual(editor1); expect(workspace.getActivePane().items).toEqual([editor0]); - - done(); }); - it('activates the pane in the dock with the matching item', async (done) => { + it('activates the pane in the dock with the matching item', async () => { const dock = atom.workspace.getRightDock(); const ITEM_URI = 'atom://test'; const item = { @@ -470,24 +440,20 @@ describe('Workspace', () => { await atom.workspace.open(ITEM_URI, { searchAllPanes: true }); expect(dock.paneForItem(item).activate).toHaveBeenCalled() - - done(); }); }); 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', async (done) => { + it('opens an editor for the given uri in the active pane', async () => { let editor = await workspace.open('a', { searchAllPanes: true }); expect(workspace.getActivePaneItem()).toBe(editor); - - done(); }); }); }); describe('when attempting to open an editor in a dock', () => { - it('opens the editor in the workspace center', async (done) => { + it('opens the editor in the workspace center', async () => { await atom.workspace.open('sample.txt', { location: 'right' }); expect( atom.workspace @@ -495,22 +461,18 @@ describe('Workspace', () => { .getActivePaneItem() .getFileName() ).toEqual('sample.txt'); - - done(); }); }); describe('when called with an item rather than a URI', () => { - it('adds the item itself to the workspace', async (done) => { + it('adds the item itself to the workspace', async () => { const item = document.createElement('div'); await atom.workspace.open(item); expect(atom.workspace.getActivePaneItem()).toBe(item); - - done(); }); describe('when the active pane already contains the item', () => { - it('activates the item', async (done) => { + it('activates the item', async () => { const item = document.createElement('div'); await atom.workspace.open(item); @@ -521,13 +483,11 @@ describe('Workspace', () => { await atom.workspace.open(item); expect(atom.workspace.getActivePaneItem()).toBe(item); expect(atom.workspace.getActivePane().getItems().length).toBe(2); - - done(); }); }); describe('when the item already exists in another pane', () => { - it('rejects the promise', async (done) => { + it('rejects the promise', async () => { const item = document.createElement('div'); await atom.workspace.open(item); @@ -545,15 +505,13 @@ describe('Workspace', () => { expect(rejection.message).toMatch( /The workspace can only contain one instance of item/ ); - - done(); }); }); }); describe("when the 'split' option is set", () => { describe("when the 'split' option is 'left'", () => { - it('opens the editor in the leftmost pane of the current pane axis', async (done) => { + it('opens the editor in the leftmost pane of the current pane axis', async () => { const pane1 = workspace.getActivePane(); const pane2 = pane1.splitRight(); expect(workspace.getActivePane()).toBe(pane2); @@ -571,13 +529,11 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane1); expect(pane1.items).toEqual([editor]); expect(pane2.items).toEqual([]); - - done(); }); }); describe('when a pane axis is the leftmost sibling of the current pane', () => { - it('opens the new item in the current pane', async (done) => { + it('opens the new item in the current pane', async () => { let editor = null; const pane1 = workspace.getActivePane(); const pane2 = pane1.splitLeft(); @@ -589,13 +545,11 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane1); expect(pane1.items).toEqual([editor]); - - done(); }); }); describe("when the 'split' option is 'right'", () => { - it('opens the editor in the rightmost pane of the current pane axis', async (done) => { + it('opens the editor in the rightmost pane of the current pane axis', async () => { let editor = null; const pane1 = workspace.getActivePane(); let pane2 = null; @@ -614,12 +568,10 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane2); expect(pane1.items).toEqual([]); expect(pane2.items).toEqual([editor]); - - done(); }); describe('when a pane axis is the rightmost sibling of the current pane', () => { - it('opens the new item in a new pane split to the right of the current pane', async (done) => { + it('opens the new item in a new pane split to the right of the current pane', async () => { let editor = null; const pane1 = workspace.getActivePane(); const pane2 = pane1.splitRight(); @@ -639,14 +591,12 @@ describe('Workspace', () => { expect(workspace.getCenter().paneContainer.root.children[1]).toBe( pane4 ); - - done(); }); }); }); describe("when the 'split' option is 'up'", () => { - it('opens the editor in the topmost pane of the current pane axis', async (done) => { + it('opens the editor in the topmost pane of the current pane axis', async () => { const pane1 = workspace.getActivePane(); const pane2 = pane1.splitDown(); expect(workspace.getActivePane()).toBe(pane2); @@ -664,13 +614,11 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane1); expect(pane1.items).toEqual([editor]); expect(pane2.items).toEqual([]); - - done(); }); }); describe('when a pane axis is the topmost sibling of the current pane', () => { - it('opens the new item in the current pane', async (done) => { + it('opens the new item in the current pane', async () => { let editor = null; const pane1 = workspace.getActivePane(); const pane2 = pane1.splitUp(); @@ -682,13 +630,11 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane1); expect(pane1.items).toEqual([editor]); - - done(); }); }); describe("when the 'split' option is 'down'", () => { - it('opens the editor in the bottommost pane of the current pane axis', async (done) => { + it('opens the editor in the bottommost pane of the current pane axis', async () => { let editor = null; const pane1 = workspace.getActivePane(); let pane2 = null; @@ -707,12 +653,10 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane2); expect(pane1.items).toEqual([]); expect(pane2.items).toEqual([editor]); - - done(); }); describe('when a pane axis is the bottommost sibling of the current pane', () => { - it('opens the new item in a new pane split to the bottom of the current pane', async (done) => { + it('opens the new item in a new pane split to the bottom of the current pane', async () => { let editor = null; const pane1 = workspace.getActivePane(); const pane2 = pane1.splitDown(); @@ -731,15 +675,13 @@ describe('Workspace', () => { expect(workspace.getCenter().paneContainer.root.children[1]).toBe( pane2 ); - - done(); }); }); }); }); describe('when an initialLine and initialColumn are specified', () => { - it('moves the cursor to the indicated location', async (done) => { + it('moves the cursor to the indicated location', async () => { await workspace.open('a', { initialLine: 1, initialColumn: 5 }); expect( @@ -778,11 +720,9 @@ describe('Workspace', () => { expect( workspace.getActiveTextEditor().getCursorBufferPosition() ).toEqual([2, 11]) - - done(); }); - it('unfolds the fold containing the line', async (done) => { + it('unfolds the fold containing the line', async () => { let editor; await workspace.open('../sample-with-many-folds.js'); @@ -796,8 +736,6 @@ describe('Workspace', () => { }); expect(editor.isFoldedAtBufferRow(2)).toBe(false); expect(editor.isFoldedAtBufferRow(3)).toBe(false); - - done(); }); }); @@ -826,30 +764,24 @@ describe('Workspace', () => { } }; - it('prompts before opening the file', async (done) => { + it('prompts before opening the file', async () => { atom.config.set('core.warnOnLargeFileLimit', 20); await shouldPromptForFileOfSize(20, true); - - done(); }); - it("doesn't prompt on files below the limit", async (done) => { + it("doesn't prompt on files below the limit", async () => { atom.config.set('core.warnOnLargeFileLimit', 30); await shouldPromptForFileOfSize(20, false); - - done(); }); - it('prompts for smaller files with a lower limit', async (done) => { + it('prompts for smaller files with a lower limit', async () => { atom.config.set('core.warnOnLargeFileLimit', 5); await shouldPromptForFileOfSize(10, true); - - done(); }); }); describe('when passed a path that matches a custom opener', () => { - it('returns the resource returned by the custom opener', async (done) => { + it('returns the resource returned by the custom opener', async () => { const fooOpener = (pathToOpen, options) => { if (pathToOpen != null ? pathToOpen.match(/\.foo/) : undefined) { return { foo: pathToOpen, options }; @@ -870,8 +802,6 @@ describe('Workspace', () => { }) expect(await workspace.open('bar://baz')).toEqual({ bar: 'bar://baz' }) - - done(); }); }); @@ -901,7 +831,7 @@ describe('Workspace', () => { done(); }); - it('notifies ::onDidAddTextEditor observers', async (done) => { + it('notifies ::onDidAddTextEditor observers', async () => { const absolutePath = require.resolve('./fixtures/dir/a'); const newEditorHandler = jasmine.createSpy('newEditorHandler'); workspace.onDidAddTextEditor(newEditorHandler); @@ -909,8 +839,6 @@ describe('Workspace', () => { let editor = await workspace.open(absolutePath); expect(newEditorHandler.calls.argsFor(0)[0].textEditor).toBe(editor); - - done(); }); describe('when there is an error opening the file', () => { @@ -922,14 +850,12 @@ describe('Workspace', () => { ); describe('when a file does not exist', () => { - it('creates an empty buffer for the specified path', async (done) => { + it('creates an empty buffer for the specified path', async () => { await workspace.open('not-a-file.md'); const editor = workspace.getActiveTextEditor(); expect(notificationSpy).not.toHaveBeenCalled(); expect(editor.getPath()).toContain('not-a-file.md'); - - done(); }); }); @@ -943,7 +869,7 @@ describe('Workspace', () => { }); }); - it('creates a notification', async (done) => { + it('creates a notification', async () => { await workspace.open('file1'); expect(notificationSpy).toHaveBeenCalled(); @@ -951,8 +877,6 @@ describe('Workspace', () => { expect(notification.getType()).toBe('warning'); expect(notification.getMessage()).toContain('Permission denied'); expect(notification.getMessage()).toContain('file1'); - - done(); }); }); @@ -966,7 +890,7 @@ describe('Workspace', () => { }); }); - it('creates a notification', async (done) => { + it('creates a notification', async () => { await workspace.open('file1'); expect(notificationSpy).toHaveBeenCalled(); @@ -974,8 +898,6 @@ describe('Workspace', () => { expect(notification.getType()).toBe('warning'); expect(notification.getMessage()).toContain('Unable to open'); expect(notification.getMessage()).toContain('file1'); - - done(); }); }); @@ -989,7 +911,7 @@ describe('Workspace', () => { }) }); - it('creates a notification', async (done) => { + it('creates a notification', async () => { await workspace.open('file1'); expect(notificationSpy).toHaveBeenCalled(); @@ -997,8 +919,6 @@ describe('Workspace', () => { expect(notification.getType()).toBe('warning'); expect(notification.getMessage()).toContain('Unable to open'); expect(notification.getMessage()).toContain('file1'); - - done(); }); }); @@ -1021,7 +941,7 @@ describe('Workspace', () => { }); describe('when the file is already open in pending state', () => { - it('should terminate the pending state', async (done) => { + it('should terminate the pending state', async () => { let editor = null; let pane = null; @@ -1033,13 +953,11 @@ describe('Workspace', () => { await atom.workspace.open('sample.js'); expect(pane.getPendingItem()).toBeNull(); - - done(); }); }); describe('when opening will switch from a pending tab to a permanent tab', () => { - it('keeps the pending tab open', async (done) => { + it('keeps the pending tab open', async () => { let editor1 = null; let editor2 = null; @@ -1050,13 +968,11 @@ describe('Workspace', () => { pane.activateItem(editor1); expect(pane.getItems().length).toBe(2); expect(pane.getItems()).toEqual([editor1, editor2]); - - done(); }); }); describe('when replacing a pending item which is the last item in a second pane', () => { - it('does not destroy the pane even if core.destroyEmptyPanes is on', async (done) => { + it('does not destroy the pane even if core.destroyEmptyPanes is on', async () => { atom.config.set('core.destroyEmptyPanes', true); let editor1 = null; let editor2 = null; @@ -1076,13 +992,11 @@ describe('Workspace', () => { expect(rightPane.getPendingItem()).toBe(editor2); expect(rightPane.destroy.calls.count()).toBe(0); - - done(); }); }); describe("when opening an editor with a buffer that isn't part of the project", () => { - it('adds the buffer to the project', async (done) => { + it('adds the buffer to the project', async () => { const buffer = new TextBuffer(); const editor = new TextEditor({ buffer }); @@ -1094,8 +1008,6 @@ describe('Workspace', () => { expect(buffer.getLanguageMode().getLanguageId()).toBe( 'text.plain.null-grammar' ); - - done(); }); }); }); @@ -1200,7 +1112,7 @@ describe('Workspace', () => { describe('::toggle(itemOrUri)', () => { 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 (done) => { + 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'; @@ -1241,13 +1153,11 @@ describe('Workspace', () => { await workspace.toggle(item2); expect(dock.isVisible()).toBe(true); expect(dock.getActivePaneItem()).toBe(item2); - - done(); }); }); 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 (done) => { + 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'; @@ -1276,8 +1186,6 @@ describe('Workspace', () => { await workspace.toggle(item1); expect(workspace.paneForItem(item1)).toBeUndefined(); expect(workspace.getActivePaneItem()).toBe(item2); - - done(); }); }); }); @@ -1444,7 +1352,7 @@ describe('Workspace', () => { }); describe('the grammar-used hook', () => { - it('fires when opening a file or changing the grammar of an open file', async (done) => { + it('fires when opening a file or changing the grammar of an open file', async () => { await atom.packages.activatePackage('language-javascript'); await atom.packages.activatePackage('language-coffee-script'); @@ -1476,13 +1384,11 @@ describe('Workspace', () => { expect(coffeeScriptGrammarUsed).not.toHaveBeenCalled(); atom.grammars.assignLanguageMode(editor, 'source.coffee'); expect(coffeeScriptGrammarUsed).toHaveBeenCalled(); - - done(); }); }); describe('the root-scope-used hook', () => { - it('fires when opening a file or changing the grammar of an open file', async (done) => { + it('fires when opening a file or changing the grammar of an open file', async () => { await atom.packages.activatePackage('language-javascript'); await atom.packages.activatePackage('language-coffee-script'); @@ -1514,13 +1420,11 @@ describe('Workspace', () => { expect(coffeeScriptGrammarUsed).not.toHaveBeenCalled(); atom.grammars.assignLanguageMode(editor, 'source.coffee'); expect(coffeeScriptGrammarUsed).toHaveBeenCalled(); - - done(); }); }); describe('the file opened hook', () => { - it('fires when opening a file', async (done) => { + it('fires when opening a file', async () => { const packageUsed = jasmine.createSpy('my-fake-package'); atom.packages.triggerDeferredActivationHooks(); @@ -1534,13 +1438,11 @@ describe('Workspace', () => { autoIndent: false }); expect(packageUsed).toHaveBeenCalled(); - - done(); }) }); describe('::reopenItem()', () => { - it("opens the uri associated with the last closed pane that isn't currently open", async (done) => { + it("opens the uri associated with the last closed pane that isn't currently open", async () => { const pane = workspace.getActivePane(); await workspace.open('a'); @@ -1594,8 +1496,6 @@ describe('Workspace', () => { expect(workspace.getActivePaneItem().getURI()).toBe( firstDirectory.resolve('file1') ) - - done(); }); }); @@ -1658,11 +1558,9 @@ describe('Workspace', () => { }); describe('::openLicense()', () => { - it('opens the license as plain-text in a buffer', async (done) => { + it('opens the license as plain-text in a buffer', async () => { await workspace.openLicense(); expect(workspace.getActivePaneItem().getText()).toMatch(/Copyright/) - - done(); }); }); @@ -1712,7 +1610,7 @@ describe('Workspace', () => { }); describe('::observeTextEditors()', () => { - it('invokes the observer with current and future text editors', async (done) => { + it('invokes the observer with current and future text editors', async () => { const observed = []; await workspace.open(); @@ -1724,8 +1622,6 @@ describe('Workspace', () => { await workspace.open(); expect(observed).toEqual(workspace.getTextEditors()); - - done(); }); }); @@ -1804,7 +1700,7 @@ describe('Workspace', () => { expect(observed).toEqual([]); }); - it('invokes the observer when closing the one and only text editor after deserialization', async (done) => { + it('invokes the observer when closing the one and only text editor after deserialization', async () => { pane.activateItem(new TextEditor()); await simulateReload(); @@ -1812,24 +1708,20 @@ describe('Workspace', () => { workspace.onDidChangeActiveTextEditor(editor => observed.push(editor)); workspace.closeActivePaneItemOrEmptyPaneOrWindow(); expect(observed).toEqual([undefined]); - - done(); }); }); describe('when an editor is destroyed', () => { - it('removes the editor', async (done) => { + it('removes the editor', async () => { const editor = await workspace.open('a'); expect(workspace.getTextEditors()).toHaveLength(1); editor.destroy(); expect(workspace.getTextEditors()).toHaveLength(0); - - done(); }); }); describe('when an editor is copied because its pane is split', () => { - it('sets up the new editor to be configured by the text editor registry', async (done) => { + it('sets up the new editor to be configured by the text editor registry', async () => { await atom.packages.activatePackage('language-javascript'); const editor = await workspace.open('a'); @@ -1841,12 +1733,10 @@ describe('Workspace', () => { const newEditor = workspace.getActiveTextEditor(); expect(newEditor).not.toBe(editor); expect(newEditor.getGrammar().name).toBe('JavaScript'); - - done(); }); }); - it('stores the active grammars used by all the open editors', async (done) => { + it('stores the active grammars used by all the open editors', async () => { await Promise.all([ atom.packages.activatePackage('language-javascript'), atom.packages.activatePackage('language-coffee-script'), @@ -1905,8 +1795,6 @@ describe('Workspace', () => { ]); atom2.destroy(); - - done(); }); describe('document.title', () => { @@ -1923,10 +1811,9 @@ describe('Workspace', () => { }); describe("when the active pane item's path is not inside a project path", () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.workspace.open('b'); atom.project.setPaths([]); - done(); }); it("sets the title to the pane item's title plus the item's path", () => { @@ -1993,10 +1880,8 @@ describe('Workspace', () => { }); describe('when the active pane item is inside a project path', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.workspace.open('b'); - - done(); }); describe('when there is an active pane item', () => { @@ -2059,13 +1944,11 @@ describe('Workspace', () => { }); describe('when the workspace is deserialized', () => { - beforeEach(async (done) => { + beforeEach(async () => { await atom.workspace.open('a'); - - done(); }); - it("updates the title to contain the project's path", async (done) => { + it("updates the title to contain the project's path", async () => { document.title = null; const atom2 = new AtomEnvironment({ @@ -2094,8 +1977,6 @@ describe('Workspace', () => { ); atom2.destroy(); - - done(); }); }); }); @@ -2104,13 +1985,11 @@ describe('Workspace', () => { let item1; let item2; - beforeEach(async (done) => { + beforeEach(async () => { await atom.workspace.open('a'); await atom.workspace.open('b'); [item1, item2] = atom.workspace.getPaneItems(); - - done(); }); it('calls setDocumentEdited when the active item changes', () => { @@ -2340,7 +2219,7 @@ describe('Workspace', () => { } describe('when called with a regex', () => { - it('calls the callback with all regex results in all files in the project', async (done) => { + it('calls the callback with all regex results in all files in the project', async () => { const results = []; await scan( /(a)+/, @@ -2363,11 +2242,9 @@ describe('Workspace', () => { leadingContextLines: [], trailingContextLines: ['cc aa cc'] }); - - done(); }); - it('works with with escaped literals (like $ and ^)', async (done) => { + it('works with with escaped literals (like $ and ^)', async () => { const results = []; await scan( /\$\w+/, @@ -2387,11 +2264,9 @@ describe('Workspace', () => { leadingContextLines: ['cc aa cc'], trailingContextLines: [] }); - - done(); }); - it('works on evil filenames', async (done) => { + it('works on evil filenames', async () => { atom.config.set('core.excludeVcsIgnoredPaths', false); platform.generateEvilFiles(); atom.project.setPaths([ @@ -2423,21 +2298,17 @@ describe('Workspace', () => { expect(paths[3]).toMatch(/quote".txt$/m); expect(path.basename(paths[4])).toBe('utfa\u0306.md'); } - - done(); }); - it('ignores case if the regex includes the `i` flag', async (done) => { + it('ignores case if the regex includes the `i` flag', async () => { const results = []; await scan(/DOLLAR/i, {}, result => results.push(result)); expect(results).toHaveLength(1); - - done(); }); if (ripgrep) { - it('returns empty text matches', async (done) => { + it('returns empty text matches', async () => { const results = []; await scan( /^\s{0}/, @@ -2463,12 +2334,10 @@ describe('Workspace', () => { leadingContextLines: [], trailingContextLines: [] }); - - done(); }); describe('newlines on regexps', () => { - it('returns multiline results from regexps', async (done) => { + it('returns multiline results from regexps', async () => { const results = []; await scan(/first\nsecond/, {}, result => results.push(result)); @@ -2489,11 +2358,9 @@ describe('Workspace', () => { leadingContextLines: [], trailingContextLines: [] }); - - done(); }); - it('returns correctly the context lines', async (done) => { + it('returns correctly the context lines', async () => { const results = []; await scan( @@ -2521,11 +2388,9 @@ describe('Workspace', () => { leadingContextLines: ['newline2', 'newline3'], trailingContextLines: ['newline4', 'newline5'] }); - - done(); }); - it('returns multiple results from the same line', async (done) => { + it('returns multiple results from the same line', async () => { const results = []; await scan(/line\d\nne/, {}, result => results.push(result)); @@ -2565,11 +2430,9 @@ describe('Workspace', () => { leadingContextLines: [], trailingContextLines: [] }); - - done(); }); - it('works with escaped newlines', async (done) => { + it('works with escaped newlines', async () => { const results = []; await scan(/second\\nthird/, {}, result => results.push(result)); @@ -2589,11 +2452,9 @@ describe('Workspace', () => { leadingContextLines: [], trailingContextLines: [] }); - - done(); }); - it('matches a regexp ending with a newline', async (done) => { + it('matches a regexp ending with a newline', async () => { const results = []; await scan(/newline3\n/, {}, result => results.push(result)); @@ -2613,12 +2474,10 @@ describe('Workspace', () => { leadingContextLines: [], trailingContextLines: [] }); - - done(); }); }); describe('pcre2 enabled', () => { - it('supports lookbehind searches', async (done) => { + it('supports lookbehind searches', async () => { const results = []; await scan(/(? @@ -2639,13 +2498,11 @@ describe('Workspace', () => { leadingContextLines: [], trailingContextLines: [] }); - - done(); }); }); } - it('returns results on lines with unicode strings', async (done) => { + it('returns results on lines with unicode strings', async () => { const results = []; await scan(/line with unico/, {}, result => results.push(result)); @@ -2663,11 +2520,9 @@ describe('Workspace', () => { leadingContextLines: [], trailingContextLines: [] }); - - done(); }); - it('returns results on files detected as binary', async (done) => { + it('returns results on files detected as binary', async () => { const results = []; await scan( @@ -2691,15 +2546,13 @@ describe('Workspace', () => { leadingContextLines: [], trailingContextLines: ['utf8Property=Fòò', 'latin1Property=F��'] }); - - done(); }); describe('when the core.excludeVcsIgnoredPaths config is used', () => { let projectPath; let ignoredPath; - beforeEach(async (done) => { + beforeEach(async () => { const sourceProjectPath = path.join( __dirname, 'fixtures', @@ -2722,8 +2575,6 @@ describe('Workspace', () => { ); ignoredPath = path.join(projectPath, 'ignored.txt'); fs.writeFileSync(ignoredPath, 'this match should not be included'); - - done(); }); afterEach(() => { @@ -2732,7 +2583,7 @@ describe('Workspace', () => { } }); - it('excludes ignored files when core.excludeVcsIgnoredPaths is true', async (done) => { + it('excludes ignored files when core.excludeVcsIgnoredPaths is true', async () => { atom.project.setPaths([projectPath]); atom.config.set('core.excludeVcsIgnoredPaths', true); const resultHandler = jasmine.createSpy('result found'); @@ -2740,11 +2591,9 @@ describe('Workspace', () => { await scan(/match/, {}, ({ filePath }) => resultHandler(filePath)); expect(resultHandler).not.toHaveBeenCalled(); - - done(); }); - it('does not exclude ignored files when core.excludeVcsIgnoredPaths is false', async (done) => { + it('does not exclude ignored files when core.excludeVcsIgnoredPaths is false', async () => { atom.project.setPaths([projectPath]); atom.config.set('core.excludeVcsIgnoredPaths', false); const resultHandler = jasmine.createSpy('result found'); @@ -2754,11 +2603,9 @@ describe('Workspace', () => { expect(resultHandler).toHaveBeenCalledWith( path.join(projectPath, 'ignored.txt') ); - - done(); }); - it('does not exclude files when searching on an ignored folder even when core.excludeVcsIgnoredPaths is true', async (done) => { + it('does not exclude files when searching on an ignored folder even when core.excludeVcsIgnoredPaths is true', async () => { fs.mkdirSync(path.join(projectPath, 'poop')); ignoredPath = path.join( path.join(projectPath, 'poop', 'whatever.txt') @@ -2774,15 +2621,13 @@ describe('Workspace', () => { ); expect(resultHandler).toHaveBeenCalledWith(ignoredPath); - - done(); }); }); describe('when the core.followSymlinks config is used', () => { let projectPath; - beforeEach(async (done) => { + beforeEach(async () => { const sourceProjectPath = path.join( __dirname, 'fixtures', @@ -2803,8 +2648,6 @@ describe('Workspace', () => { path.join(__dirname, 'fixtures', 'dir', 'b'), path.join(projectPath, 'symlink') ); - - done(); }); afterEach(() => { @@ -2813,7 +2656,7 @@ describe('Workspace', () => { } }); - it('follows symlinks when core.followSymlinks is true', async (done) => { + it('follows symlinks when core.followSymlinks is true', async () => { atom.project.setPaths([projectPath]); atom.config.set('core.followSymlinks', true); const resultHandler = jasmine.createSpy('result found'); @@ -2823,11 +2666,9 @@ describe('Workspace', () => { expect(resultHandler).toHaveBeenCalledWith( path.join(projectPath, 'symlink') ); - - done(); }); - it('does not follow symlinks when core.followSymlinks is false', async (done) => { + it('does not follow symlinks when core.followSymlinks is false', async () => { atom.project.setPaths([projectPath]); atom.config.set('core.followSymlinks', false); const resultHandler = jasmine.createSpy('result found'); @@ -2835,15 +2676,13 @@ describe('Workspace', () => { await scan(/ccc/, {}, ({ filePath }) => resultHandler(filePath)); expect(resultHandler).not.toHaveBeenCalled(); - - done(); }); }); describe('when there are hidden files', () => { let projectPath; - beforeEach(async (done) => { + beforeEach(async () => { const sourceProjectPath = path.join( __dirname, 'fixtures', @@ -2864,8 +2703,6 @@ describe('Workspace', () => { // accurately test this behaviour there, we should either use a package // like `fswin` or manually spawn an `ATTRIB` command. fs.writeFileSync(path.join(projectPath, '.hidden'), 'ccc'); - - done(); }); afterEach(() => { @@ -2874,7 +2711,7 @@ describe('Workspace', () => { } }); - it('searches on hidden files', async (done) => { + it('searches on hidden files', async () => { atom.project.setPaths([projectPath]); const resultHandler = jasmine.createSpy('result found'); @@ -2883,12 +2720,10 @@ describe('Workspace', () => { expect(resultHandler).toHaveBeenCalledWith( path.join(projectPath, '.hidden') ); - - done(); }); }); - it('includes only files when a directory filter is specified', async (done) => { + it('includes only files when a directory filter is specified', async () => { const projectPath = path.join( path.join(__dirname, 'fixtures', 'dir') ); @@ -2907,11 +2742,9 @@ describe('Workspace', () => { expect(paths.length).toBe(1); expect(paths[0]).toBe(filePath); expect(matches.length).toBe(1); - - done(); }); - it("includes files and folders that begin with a '.'", async (done) => { + it("includes files and folders that begin with a '.'", async () => { const projectPath = temp.mkdirSync('atom-spec-workspace'); const filePath = path.join(projectPath, '.text'); fs.writeFileSync(filePath, 'match this'); @@ -2927,11 +2760,9 @@ describe('Workspace', () => { expect(paths.length).toBe(1); expect(paths[0]).toBe(filePath); expect(matches.length).toBe(1); - - done(); }); - it('excludes values in core.ignoredNames', async (done) => { + it('excludes values in core.ignoredNames', async () => { const ignoredNames = atom.config.get('core.ignoredNames'); ignoredNames.push('a'); atom.config.set('core.ignoredNames', ignoredNames); @@ -2940,11 +2771,9 @@ describe('Workspace', () => { await scan(/dollar/, {}, () => resultHandler()); expect(resultHandler).not.toHaveBeenCalled(); - - done(); }); - it('scans buffer contents if the buffer is modified', async (done) => { + it('scans buffer contents if the buffer is modified', async () => { const results = []; const editor = await atom.workspace.open('a'); @@ -2959,11 +2788,9 @@ describe('Workspace', () => { ); expect(resultForA.matches).toHaveLength(1); expect(resultForA.matches[0].matchText).toBe('Elephant'); - - done(); }); - it('ignores buffers outside the project', async (done) => { + it('ignores buffers outside the project', async () => { const results = []; const editor = await atom.workspace.open(temp.openSync().path); @@ -2972,8 +2799,6 @@ describe('Workspace', () => { await scan(/Elephant/, {}, result => results.push(result)); expect(results).toHaveLength(0); - - done(); }); describe('when the project has multiple root directories', () => { @@ -2995,7 +2820,7 @@ describe('Workspace', () => { atom.project.addPath(dir2); }); - it("searches matching files in all of the project's root directories", async (done) => { + it("searches matching files in all of the project's root directories", async () => { const resultPaths = []; await scan(/aaaa/, {}, ({ filePath }) => @@ -3003,12 +2828,10 @@ describe('Workspace', () => { ); expect(resultPaths.sort()).toEqual([file1, file2].sort()); - - done(); }); describe('when an inclusion path starts with the basename of a root directory', () => { - it('interprets the inclusion path as starting from that directory', async (done) => { + it('interprets the inclusion path as starting from that directory', async () => { let resultPaths = []; await scan(/aaaa/, { paths: ['dir'] }, ({ filePath }) => { if (!resultPaths.includes(filePath)) { @@ -3056,8 +2879,6 @@ describe('Workspace', () => { ); expect(resultPaths).toEqual([file2]); - - done(); }); }); @@ -3107,7 +2928,7 @@ describe('Workspace', () => { ); }); - it('can override the DefaultDirectorySearcher on a per-directory basis', async (done) => { + it('can override the DefaultDirectorySearcher on a per-directory basis', async () => { const foreignFilePath = 'ssh://foreign-directory:8080/hello.txt'; const numPathsSearchedInDir2 = 1; const numPathsToPretendToSearchInCustomDirectorySearcher = 10; @@ -3148,11 +2969,9 @@ describe('Workspace', () => { numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2 ); - - done(); }); - it('can be cancelled when the object returned by scan() has its cancel() method invoked', async (done) => { + it('can be cancelled when the object returned by scan() has its cancel() method invoked', async () => { const thenable = scan(/aaaa/, {}, () => {}); let resultOfPromiseSearch = null; @@ -3163,11 +2982,9 @@ describe('Workspace', () => { resultOfPromiseSearch = await thenable; expect(resultOfPromiseSearch).toBe('cancelled'); - - done(); }); - it('will have the side-effect of failing the overall search if it fails', async (done) => { + it('will have the side-effect of failing the overall search if it fails', async () => { // This provider's search should be cancelled when the first provider fails let cancelableSearch; let fakeSearch2 = null; @@ -3198,8 +3015,6 @@ describe('Workspace', () => { expect(cancelableSearchCatchSpy).toHaveBeenCalled(); expect(fakeSearch2.cancelled).toBe(true); - - done(); }); }); }); @@ -3240,7 +3055,7 @@ describe('Workspace', () => { ['line 13', 'line 14', 'line 15'] ]; - it('returns valid contexts no matter how many lines are requested', async (done) => { + it('returns valid contexts no matter how many lines are requested', async () => { expect(await search({})).toEqual({ leadingContext: [[], [], [], []], trailingContext: [[], [], [], []] @@ -3301,8 +3116,6 @@ describe('Workspace', () => { result.slice(0, 3) ) }); - - done(); }); }); }); // Cancels other ongoing searches @@ -3318,7 +3131,7 @@ describe('Workspace', () => { }); describe("when a file doesn't exist", () => { - it('calls back with an error', async (done) => { + it('calls back with an error', async () => { const errors = []; const missingPath = path.resolve('/not-a-file.js'); expect(fs.existsSync(missingPath)).toBeFalsy(); @@ -3332,13 +3145,11 @@ describe('Workspace', () => { expect(errors).toHaveLength(1); expect(errors[0].path).toBe(missingPath); - - done(); }); }); describe('when called with unopened files', () => { - it('replaces properly', async (done) => { + it('replaces properly', async () => { const filePath = path.join(projectDir, 'sample.js'); fs.copyFileSync(path.join(fixturesDir, 'sample.js'), filePath); @@ -3350,11 +3161,9 @@ describe('Workspace', () => { expect(results).toHaveLength(1); expect(results[0].filePath).toBe(filePath); expect(results[0].replacements).toBe(6); - - done(); }); - it('does not discard the multiline flag', async (done) => { + it('does not discard the multiline flag', async () => { const filePath = path.join(projectDir, 'sample.js'); fs.copyFileSync(path.join(fixturesDir, 'sample.js'), filePath); @@ -3366,13 +3175,11 @@ describe('Workspace', () => { expect(results).toHaveLength(1); expect(results[0].filePath).toBe(filePath); expect(results[0].replacements).toBe(8); - - done(); }); }); describe('when a buffer is already open', () => { - it('replaces properly and saves when not modified', async (done) => { + it('replaces properly and saves when not modified', async () => { const filePath = path.join(projectDir, 'sample.js'); fs.copyFileSync( path.join(fixturesDir, 'sample.js'), @@ -3395,11 +3202,9 @@ describe('Workspace', () => { expect(results[0].replacements).toBe(6); expect(editor.isModified()).toBeFalsy(); - - done(); }); - it('does not replace when the path is not specified', async (done) => { + it('does not replace when the path is not specified', async () => { const filePath = path.join(projectDir, 'sample.js'); const commentFilePath = path.join( projectDir, @@ -3423,11 +3228,9 @@ describe('Workspace', () => { expect(results).toHaveLength(1); expect(results[0].filePath).toBe(commentFilePath); - - done(); }); - it('does NOT save when modified', async (done) => { + it('does NOT save when modified', async () => { const filePath = path.join(projectDir, 'sample.js'); fs.copyFileSync(path.join(fixturesDir, 'sample.js'), filePath); @@ -3448,8 +3251,6 @@ describe('Workspace', () => { expect(results[0].replacements).toBe(6); expect(editor.isModified()).toBeTruthy(); - - done(); }); }); }); @@ -3457,17 +3258,15 @@ describe('Workspace', () => { describe('::saveActivePaneItem()', () => { let editor, notificationSpy; - beforeEach(async (done) => { + beforeEach(async () => { editor = await atom.workspace.open('sample.js'); notificationSpy = jasmine.createSpy('did-add-notification'); atom.notifications.onDidAddNotification(notificationSpy); - - done(); }); describe('when there is an error', () => { - it('emits a warning notification when the file cannot be saved', async (done) => { + it('emits a warning notification when the file cannot be saved', async () => { spyOn(editor, 'save').and.callFake(() => { throw new Error("'/some/file' is a directory"); }); @@ -3481,11 +3280,9 @@ describe('Workspace', () => { expect( notificationSpy.calls.mostRecent().args[0].getMessage() ).toContain('Unable to save'); - - done(); }); - it('emits a warning notification when the directory cannot be written to', async (done) => { + it('emits a warning notification when the directory cannot be written to', async () => { spyOn(editor, 'save').and.callFake(() => { throw new Error("ENOTDIR, not a directory '/Some/dir/and-a-file.js'"); }); @@ -3499,11 +3296,9 @@ describe('Workspace', () => { expect( notificationSpy.calls.mostRecent().args[0].getMessage() ).toContain('Unable to save'); - - done(); }); - it('emits a warning notification when the user does not have permission', async (done) => { + it('emits a warning notification when the user does not have permission', async () => { spyOn(editor, 'save').and.callFake(() => { const error = new Error( "EACCES, permission denied '/Some/dir/and-a-file.js'" @@ -3522,11 +3317,9 @@ describe('Workspace', () => { expect( notificationSpy.calls.mostRecent().args[0].getMessage() ).toContain('Unable to save'); - - done(); }); - it('emits a warning notification when the operation is not permitted', async (done) => { + it('emits a warning notification when the operation is not permitted', async () => { spyOn(editor, 'save').and.callFake(() => { const error = new Error( "EPERM, operation not permitted '/Some/dir/and-a-file.js'" @@ -3545,11 +3338,9 @@ describe('Workspace', () => { expect( notificationSpy.calls.mostRecent().args[0].getMessage() ).toContain('Unable to save'); - - done(); }); - it('emits a warning notification when the file is already open by another app', async (done) => { + it('emits a warning notification when the file is already open by another app', async () => { spyOn(editor, 'save').and.callFake(() => { const error = new Error( "EBUSY, resource busy or locked '/Some/dir/and-a-file.js'" @@ -3568,11 +3359,9 @@ describe('Workspace', () => { expect( notificationSpy.calls.mostRecent().args[0].getMessage() ).toContain('Unable to save'); - - done(); }); - it('emits a warning notification when the file system is read-only', async (done) => { + it('emits a warning notification when the file system is read-only', async () => { spyOn(editor, 'save').and.callFake(() => { const error = new Error( "EROFS, read-only file system '/Some/dir/and-a-file.js'" @@ -3591,11 +3380,9 @@ describe('Workspace', () => { expect( notificationSpy.calls.mostRecent().args[0].getMessage() ).toContain('Unable to save'); - - done(); }); - it('emits a warning notification when the file cannot be saved', async (done) => { + it('emits a warning notification when the file cannot be saved', async () => { spyOn(editor, 'save').and.callFake(() => { throw new Error('no one knows'); }); @@ -3604,21 +3391,17 @@ describe('Workspace', () => { await atom.workspace.saveActivePaneItem().catch(catchSpy) expect(catchSpy).toHaveBeenCalled(); - - done(); }); }); }); describe('::closeActivePaneItemOrEmptyPaneOrWindow', () => { - beforeEach(async (done) => { + beforeEach(async () => { spyOn(atom, 'close'); await atom.workspace.open(); - - done(); }); - it('closes the active center pane item, or the active center pane if it is empty, or the current window if there is only the empty root pane in the center', async (done) => { + it('closes the active center pane item, or the active center pane if it is empty, or the current window if there is only the empty root pane in the center', async () => { atom.config.set('core.destroyEmptyPanes', false); const pane1 = atom.workspace.getActivePane(); @@ -3657,8 +3440,6 @@ describe('Workspace', () => { expect(atom.workspace.getLeftDock().getPaneItems().length).toBe(2); atom.workspace.closeActivePaneItemOrEmptyPaneOrWindow(); expect(atom.close).toHaveBeenCalled(); - - done(); }); }); @@ -3794,7 +3575,7 @@ describe('Workspace', () => { }); describe('when the core.allowPendingPaneItems option is falsy', () => { - it('does not open item with `pending: true` option as pending', async (done) => { + it('does not open item with `pending: true` option as pending', async () => { let pane = null; atom.config.set('core.allowPendingPaneItems', false); @@ -3802,13 +3583,11 @@ describe('Workspace', () => { pane = atom.workspace.getActivePane(); expect(pane.getPendingItem()).toBeFalsy(); - - done(); }); }); describe('grammar activation', () => { - it('notifies the workspace of which grammar is used', async (done) => { + it('notifies the workspace of which grammar is used', async () => { atom.packages.triggerDeferredActivationHooks(); const javascriptGrammarUsed = jasmine.createSpy('js grammar used'); @@ -3850,23 +3629,19 @@ describe('Workspace', () => { 'source.ruby' ); expect(rubyGrammarUsed).toHaveBeenCalled(); - - done(); }); }); describe('.checkoutHeadRevision()', () => { let editor = null; - beforeEach(async (done) => { + beforeEach(async () => { jasmine.useRealClock(); atom.config.set('editor.confirmCheckoutHeadRevision', false); editor = await atom.workspace.open('sample-with-comments.js'); - - done(); }); - it('reverts to the version of its file checked into the project repository', async (done) => { + it('reverts to the version of its file checked into the project repository', async () => { editor.setCursorBufferPosition([0, 0]); editor.insertText('---\n'); expect(editor.lineTextForBufferRow(0)).toBe('---'); @@ -3874,8 +3649,6 @@ describe('Workspace', () => { atom.workspace.checkoutHeadRevision(editor); await conditionPromise(() => editor.lineTextForBufferRow(0) === ''); - - done(); }); describe("when there's no repository for the editor's file", () => { @@ -3894,11 +3667,9 @@ describe('Workspace', () => { atom.workspace.enablePersistence = true; }); - afterEach(async (done) => { + afterEach(async () => { await atom.workspace.itemLocationStore.clear(); atom.workspace.enablePersistence = false; - - done(); }); it("stores the new location if it's not the default", () => {