2017-09-29 02:18:56 +03:00
const path = require ( 'path' )
2017-10-03 23:20:48 +03:00
const url = require ( 'url' )
2017-09-29 02:18:56 +03:00
const Package = require ( '../src/package' )
const PackageManager = require ( '../src/package-manager' )
const temp = require ( 'temp' ) . track ( )
const fs = require ( 'fs-plus' )
2019-02-22 10:55:17 +03:00
const { Disposable } = require ( 'atom' )
const { buildKeydownEvent } = require ( '../src/keymap-extensions' )
const { mockLocalStorage } = require ( './spec-helper' )
2017-09-29 02:18:56 +03:00
const ModuleCache = require ( '../src/module-cache' )
describe ( 'PackageManager' , ( ) => {
function createTestElement ( className ) {
const element = document . createElement ( 'div' )
element . className = className
return element
}
beforeEach ( ( ) => {
spyOn ( ModuleCache , 'add' )
} )
describe ( 'initialize' , ( ) => {
it ( 'adds regular package path' , ( ) => {
const packageManger = new PackageManager ( { } )
const configDirPath = path . join ( '~' , 'someConfig' )
2019-02-22 10:55:17 +03:00
packageManger . initialize ( { configDirPath } )
2017-09-29 02:18:56 +03:00
expect ( packageManger . packageDirPaths . length ) . toBe ( 1 )
2019-02-22 10:55:17 +03:00
expect ( packageManger . packageDirPaths [ 0 ] ) . toBe (
path . join ( configDirPath , 'packages' )
)
2017-09-29 02:18:56 +03:00
} )
2018-07-14 03:29:06 +03:00
it ( 'adds regular package path, dev package path, and Atom repo package path in dev mode and dev resource path is set' , ( ) => {
2017-09-29 02:18:56 +03:00
const packageManger = new PackageManager ( { } )
const configDirPath = path . join ( '~' , 'someConfig' )
2018-07-14 03:29:06 +03:00
const resourcePath = path . join ( '~' , '/atom' )
2019-02-22 10:55:17 +03:00
packageManger . initialize ( { configDirPath , resourcePath , devMode : true } )
2018-07-14 03:29:06 +03:00
expect ( packageManger . packageDirPaths . length ) . toBe ( 3 )
2019-02-22 10:55:17 +03:00
expect ( packageManger . packageDirPaths ) . toContain (
path . join ( configDirPath , 'packages' )
)
expect ( packageManger . packageDirPaths ) . toContain (
path . join ( configDirPath , 'dev' , 'packages' )
)
expect ( packageManger . packageDirPaths ) . toContain (
path . join ( resourcePath , 'packages' )
)
2017-09-29 02:18:56 +03:00
} )
} )
describe ( '::getApmPath()' , ( ) => {
it ( 'returns the path to the apm command' , ( ) => {
let apmPath = path . join ( process . resourcesPath , 'app' , 'apm' , 'bin' , 'apm' )
if ( process . platform === 'win32' ) {
apmPath += '.cmd'
}
expect ( atom . packages . getApmPath ( ) ) . toBe ( apmPath )
} )
describe ( 'when the core.apmPath setting is set' , ( ) => {
beforeEach ( ( ) => atom . config . set ( 'core.apmPath' , '/path/to/apm' ) )
2017-09-29 03:09:55 +03:00
it ( 'returns the value of the core.apmPath config setting' , ( ) => {
expect ( atom . packages . getApmPath ( ) ) . toBe ( '/path/to/apm' )
} )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( '::loadPackages()' , ( ) => {
beforeEach ( ( ) => spyOn ( atom . packages , 'loadAvailablePackage' ) )
2017-09-29 03:04:46 +03:00
afterEach ( async ( ) => {
await atom . packages . deactivatePackages ( )
atom . packages . unloadPackages ( )
2017-09-29 02:18:56 +03:00
} )
it ( 'sets hasLoadedInitialPackages' , ( ) => {
expect ( atom . packages . hasLoadedInitialPackages ( ) ) . toBe ( false )
atom . packages . loadPackages ( )
expect ( atom . packages . hasLoadedInitialPackages ( ) ) . toBe ( true )
} )
} )
describe ( '::loadPackage(name)' , ( ) => {
beforeEach ( ( ) => atom . config . set ( 'core.disabledPackages' , [ ] ) )
it ( 'returns the package' , ( ) => {
const pack = atom . packages . loadPackage ( 'package-with-index' )
expect ( pack instanceof Package ) . toBe ( true )
expect ( pack . metadata . name ) . toBe ( 'package-with-index' )
} )
it ( 'returns the package if it has an invalid keymap' , ( ) => {
spyOn ( atom , 'inSpecMode' ) . andReturn ( false )
const pack = atom . packages . loadPackage ( 'package-with-broken-keymap' )
expect ( pack instanceof Package ) . toBe ( true )
expect ( pack . metadata . name ) . toBe ( 'package-with-broken-keymap' )
} )
it ( 'returns the package if it has an invalid stylesheet' , ( ) => {
spyOn ( atom , 'inSpecMode' ) . andReturn ( false )
const pack = atom . packages . loadPackage ( 'package-with-invalid-styles' )
expect ( pack instanceof Package ) . toBe ( true )
expect ( pack . metadata . name ) . toBe ( 'package-with-invalid-styles' )
expect ( pack . stylesheets . length ) . toBe ( 0 )
const addErrorHandler = jasmine . createSpy ( )
atom . notifications . onDidAddNotification ( addErrorHandler )
expect ( ( ) => pack . reloadStylesheets ( ) ) . not . toThrow ( )
expect ( addErrorHandler . callCount ) . toBe ( 2 )
2019-02-22 10:55:17 +03:00
expect ( addErrorHandler . argsForCall [ 1 ] [ 0 ] . message ) . toContain (
'Failed to reload the package-with-invalid-styles package stylesheets'
)
expect ( addErrorHandler . argsForCall [ 1 ] [ 0 ] . options . packageName ) . toEqual (
'package-with-invalid-styles'
)
2017-09-29 02:18:56 +03:00
} )
it ( 'returns null if the package has an invalid package.json' , ( ) => {
spyOn ( atom , 'inSpecMode' ) . andReturn ( false )
const addErrorHandler = jasmine . createSpy ( )
atom . notifications . onDidAddNotification ( addErrorHandler )
2019-02-22 10:55:17 +03:00
expect (
atom . packages . loadPackage ( 'package-with-broken-package-json' )
) . toBeNull ( )
2017-09-29 02:18:56 +03:00
expect ( addErrorHandler . callCount ) . toBe ( 1 )
2019-02-22 10:55:17 +03:00
expect ( addErrorHandler . argsForCall [ 0 ] [ 0 ] . message ) . toContain (
'Failed to load the package-with-broken-package-json package'
)
expect ( addErrorHandler . argsForCall [ 0 ] [ 0 ] . options . packageName ) . toEqual (
'package-with-broken-package-json'
)
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:09:55 +03:00
it ( 'returns null if the package name or path starts with a dot' , ( ) => {
2019-02-22 10:55:17 +03:00
expect (
atom . packages . loadPackage ( '/Users/user/.atom/packages/.git' )
) . toBeNull ( )
2017-09-29 03:09:55 +03:00
} )
2017-09-29 02:18:56 +03:00
it ( 'normalizes short repository urls in package.json' , ( ) => {
2019-02-22 10:55:17 +03:00
let { metadata } = atom . packages . loadPackage (
'package-with-short-url-package-json'
)
2017-09-29 02:18:56 +03:00
expect ( metadata . repository . type ) . toBe ( 'git' )
2019-02-22 10:55:17 +03:00
expect ( metadata . repository . url ) . toBe ( 'https://github.com/example/repo' )
; ( { metadata } = atom . packages . loadPackage (
'package-with-invalid-url-package-json'
) )
2017-09-29 02:18:56 +03:00
expect ( metadata . repository . type ) . toBe ( 'git' )
expect ( metadata . repository . url ) . toBe ( 'foo' )
} )
it ( 'trims git+ from the beginning and .git from the end of repository URLs, even if npm already normalized them ' , ( ) => {
2019-02-22 10:55:17 +03:00
const { metadata } = atom . packages . loadPackage (
'package-with-prefixed-and-suffixed-repo-url'
)
2017-09-29 02:18:56 +03:00
expect ( metadata . repository . type ) . toBe ( 'git' )
expect ( metadata . repository . url ) . toBe ( 'https://github.com/example/repo' )
} )
it ( 'returns null if the package is not found in any package directory' , ( ) => {
spyOn ( console , 'warn' )
2019-02-22 10:55:17 +03:00
expect (
atom . packages . loadPackage ( 'this-package-cannot-be-found' )
) . toBeNull ( )
2017-09-29 02:18:56 +03:00
expect ( console . warn . callCount ) . toBe ( 1 )
expect ( console . warn . argsForCall [ 0 ] [ 0 ] ) . toContain ( 'Could not resolve' )
} )
describe ( 'when the package is deprecated' , ( ) => {
it ( 'returns null' , ( ) => {
spyOn ( console , 'warn' )
2019-02-22 10:55:17 +03:00
expect (
atom . packages . loadPackage (
path . join ( _ _dirname , 'fixtures' , 'packages' , 'wordcount' )
)
) . toBeNull ( )
expect ( atom . packages . isDeprecatedPackage ( 'wordcount' , '2.1.9' ) ) . toBe (
true
)
expect ( atom . packages . isDeprecatedPackage ( 'wordcount' , '2.2.0' ) ) . toBe (
true
)
expect ( atom . packages . isDeprecatedPackage ( 'wordcount' , '2.2.1' ) ) . toBe (
false
)
expect (
atom . packages . getDeprecatedPackageMetadata ( 'wordcount' ) . version
) . toBe ( '<=2.2.0' )
2017-09-29 02:18:56 +03:00
} )
} )
it ( 'invokes ::onDidLoadPackage listeners with the loaded package' , ( ) => {
let loadedPackage = null
atom . packages . onDidLoadPackage ( pack => {
loadedPackage = pack
} )
atom . packages . loadPackage ( 'package-with-main' )
expect ( loadedPackage . name ) . toBe ( 'package-with-main' )
} )
it ( "registers any deserializers specified in the package's package.json" , ( ) => {
atom . packages . loadPackage ( 'package-with-deserializers' )
2019-02-22 10:55:17 +03:00
const state1 = { deserializer : 'Deserializer1' , a : 'b' }
2017-09-29 02:18:56 +03:00
expect ( atom . deserializers . deserialize ( state1 ) ) . toEqual ( {
wasDeserializedBy : 'deserializeMethod1' ,
state : state1
} )
2019-02-22 10:55:17 +03:00
const state2 = { deserializer : 'Deserializer2' , c : 'd' }
2017-09-29 02:18:56 +03:00
expect ( atom . deserializers . deserialize ( state2 ) ) . toEqual ( {
wasDeserializedBy : 'deserializeMethod2' ,
state : state2
} )
} )
it ( 'early-activates any atom.directory-provider or atom.repository-provider services that the package provide' , ( ) => {
jasmine . useRealClock ( )
const providers = [ ]
2019-02-22 10:55:17 +03:00
atom . packages . serviceHub . consume (
'atom.directory-provider' ,
'^0.1.0' ,
provider => providers . push ( provider )
)
2017-09-29 02:18:56 +03:00
atom . packages . loadPackage ( 'package-with-directory-provider' )
2019-02-22 10:55:17 +03:00
expect ( providers . map ( p => p . name ) ) . toEqual ( [
'directory provider from package-with-directory-provider'
] )
2017-09-29 02:18:56 +03:00
} )
describe ( "when there are view providers specified in the package's package.json" , ( ) => {
2019-02-22 10:55:17 +03:00
const model1 = { worksWithViewProvider1 : true }
const model2 = { worksWithViewProvider2 : true }
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
afterEach ( async ( ) => {
await atom . packages . deactivatePackage ( 'package-with-view-providers' )
atom . packages . unloadPackage ( 'package-with-view-providers' )
2017-09-29 02:18:56 +03:00
} )
it ( 'does not load the view providers immediately' , ( ) => {
const pack = atom . packages . loadPackage ( 'package-with-view-providers' )
expect ( pack . mainModule ) . toBeNull ( )
expect ( ( ) => atom . views . getView ( model1 ) ) . toThrow ( )
expect ( ( ) => atom . views . getView ( model2 ) ) . toThrow ( )
} )
2017-09-29 03:04:46 +03:00
it ( 'registers the view providers when the package is activated' , async ( ) => {
2017-09-29 02:18:56 +03:00
atom . packages . loadPackage ( 'package-with-view-providers' )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-view-providers' )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
const element1 = atom . views . getView ( model1 )
expect ( element1 instanceof HTMLDivElement ) . toBe ( true )
expect ( element1 . dataset . createdBy ) . toBe ( 'view-provider-1' )
const element2 = atom . views . getView ( model2 )
expect ( element2 instanceof HTMLDivElement ) . toBe ( true )
expect ( element2 . dataset . createdBy ) . toBe ( 'view-provider-2' )
2017-09-29 02:18:56 +03:00
} )
it ( "registers the view providers when any of the package's deserializers are used" , ( ) => {
atom . packages . loadPackage ( 'package-with-view-providers' )
spyOn ( atom . views , 'addViewProvider' ) . andCallThrough ( )
atom . deserializers . deserialize ( {
deserializer : 'DeserializerFromPackageWithViewProviders' ,
a : 'b'
} )
expect ( atom . views . addViewProvider . callCount ) . toBe ( 2 )
atom . deserializers . deserialize ( {
deserializer : 'DeserializerFromPackageWithViewProviders' ,
a : 'b'
} )
expect ( atom . views . addViewProvider . callCount ) . toBe ( 2 )
const element1 = atom . views . getView ( model1 )
expect ( element1 instanceof HTMLDivElement ) . toBe ( true )
expect ( element1 . dataset . createdBy ) . toBe ( 'view-provider-1' )
const element2 = atom . views . getView ( model2 )
expect ( element2 instanceof HTMLDivElement ) . toBe ( true )
expect ( element2 . dataset . createdBy ) . toBe ( 'view-provider-2' )
} )
} )
it ( "registers the config schema in the package's metadata, if present" , ( ) => {
let pack = atom . packages . loadPackage ( 'package-with-json-config-schema' )
expect ( atom . config . getSchema ( 'package-with-json-config-schema' ) ) . toEqual ( {
type : 'object' ,
properties : {
2019-02-22 10:55:17 +03:00
a : { type : 'number' , default : 5 } ,
b : { type : 'string' , default : 'five' }
2017-09-29 02:18:56 +03:00
}
} )
expect ( pack . mainModule ) . toBeNull ( )
atom . packages . unloadPackage ( 'package-with-json-config-schema' )
atom . config . clear ( )
pack = atom . packages . loadPackage ( 'package-with-json-config-schema' )
expect ( atom . config . getSchema ( 'package-with-json-config-schema' ) ) . toEqual ( {
type : 'object' ,
properties : {
2019-02-22 10:55:17 +03:00
a : { type : 'number' , default : 5 } ,
b : { type : 'string' , default : 'five' }
2017-09-29 02:18:56 +03:00
}
} )
} )
describe ( 'when a package does not have deserializers, view providers or a config schema in its package.json' , ( ) => {
beforeEach ( ( ) => mockLocalStorage ( ) )
it ( "defers loading the package's main module if the package previously used no Atom APIs when its main module was required" , ( ) => {
const pack1 = atom . packages . loadPackage ( 'package-with-main' )
expect ( pack1 . mainModule ) . toBeDefined ( )
atom . packages . unloadPackage ( 'package-with-main' )
const pack2 = atom . packages . loadPackage ( 'package-with-main' )
expect ( pack2 . mainModule ) . toBeNull ( )
} )
it ( "does not defer loading the package's main module if the package previously used Atom APIs when its main module was required" , ( ) => {
2019-02-22 10:55:17 +03:00
const pack1 = atom . packages . loadPackage (
'package-with-eval-time-api-calls'
)
2017-09-29 02:18:56 +03:00
expect ( pack1 . mainModule ) . toBeDefined ( )
atom . packages . unloadPackage ( 'package-with-eval-time-api-calls' )
2019-02-22 10:55:17 +03:00
const pack2 = atom . packages . loadPackage (
'package-with-eval-time-api-calls'
)
2017-09-29 02:18:56 +03:00
expect ( pack2 . mainModule ) . not . toBeNull ( )
} )
} )
} )
describe ( '::loadAvailablePackage(availablePackage)' , ( ) => {
describe ( 'if the package was preloaded' , ( ) => {
it ( 'adds the package path to the module cache' , ( ) => {
2019-02-22 10:55:17 +03:00
const availablePackage = atom . packages
. getAvailablePackages ( )
. find ( p => p . name === 'spell-check' )
2017-09-29 02:18:56 +03:00
availablePackage . isBundled = true
2019-02-22 10:55:17 +03:00
expect (
atom . packages . preloadedPackages [ availablePackage . name ]
) . toBeUndefined ( )
2017-09-29 02:18:56 +03:00
expect ( atom . packages . isPackageLoaded ( availablePackage . name ) ) . toBe ( false )
const metadata = atom . packages . loadPackageMetadata ( availablePackage )
2019-02-22 10:55:17 +03:00
atom . packages . preloadPackage ( availablePackage . name , {
rootDirPath : path . relative (
atom . packages . resourcePath ,
availablePackage . path
) ,
metadata
} )
2017-09-29 02:18:56 +03:00
atom . packages . loadAvailablePackage ( availablePackage )
expect ( atom . packages . isPackageLoaded ( availablePackage . name ) ) . toBe ( true )
2019-02-22 10:55:17 +03:00
expect ( ModuleCache . add ) . toHaveBeenCalledWith (
availablePackage . path ,
metadata
)
2017-09-29 02:18:56 +03:00
} )
it ( 'deactivates it if it had been disabled' , ( ) => {
2019-02-22 10:55:17 +03:00
const availablePackage = atom . packages
. getAvailablePackages ( )
. find ( p => p . name === 'spell-check' )
2017-09-29 02:18:56 +03:00
availablePackage . isBundled = true
2019-02-22 10:55:17 +03:00
expect (
atom . packages . preloadedPackages [ availablePackage . name ]
) . toBeUndefined ( )
2017-09-29 02:18:56 +03:00
expect ( atom . packages . isPackageLoaded ( availablePackage . name ) ) . toBe ( false )
const metadata = atom . packages . loadPackageMetadata ( availablePackage )
const preloadedPackage = atom . packages . preloadPackage (
availablePackage . name ,
{
2019-02-22 10:55:17 +03:00
rootDirPath : path . relative (
atom . packages . resourcePath ,
availablePackage . path
) ,
2017-09-29 02:18:56 +03:00
metadata
}
)
expect ( preloadedPackage . keymapActivated ) . toBe ( true )
expect ( preloadedPackage . settingsActivated ) . toBe ( true )
expect ( preloadedPackage . menusActivated ) . toBe ( true )
2019-02-22 10:55:17 +03:00
atom . packages . loadAvailablePackage (
availablePackage ,
new Set ( [ availablePackage . name ] )
)
2017-09-29 02:18:56 +03:00
expect ( atom . packages . isPackageLoaded ( availablePackage . name ) ) . toBe ( false )
expect ( preloadedPackage . keymapActivated ) . toBe ( false )
expect ( preloadedPackage . settingsActivated ) . toBe ( false )
expect ( preloadedPackage . menusActivated ) . toBe ( false )
} )
it ( 'deactivates it and reloads the new one if trying to load the same package outside of the bundle' , ( ) => {
2019-02-22 10:55:17 +03:00
const availablePackage = atom . packages
. getAvailablePackages ( )
. find ( p => p . name === 'spell-check' )
2017-09-29 02:18:56 +03:00
availablePackage . isBundled = true
2019-02-22 10:55:17 +03:00
expect (
atom . packages . preloadedPackages [ availablePackage . name ]
) . toBeUndefined ( )
2017-09-29 02:18:56 +03:00
expect ( atom . packages . isPackageLoaded ( availablePackage . name ) ) . toBe ( false )
const metadata = atom . packages . loadPackageMetadata ( availablePackage )
const preloadedPackage = atom . packages . preloadPackage (
availablePackage . name ,
{
2019-02-22 10:55:17 +03:00
rootDirPath : path . relative (
atom . packages . resourcePath ,
availablePackage . path
) ,
2017-09-29 02:18:56 +03:00
metadata
}
)
expect ( preloadedPackage . keymapActivated ) . toBe ( true )
expect ( preloadedPackage . settingsActivated ) . toBe ( true )
expect ( preloadedPackage . menusActivated ) . toBe ( true )
availablePackage . isBundled = false
atom . packages . loadAvailablePackage ( availablePackage )
expect ( atom . packages . isPackageLoaded ( availablePackage . name ) ) . toBe ( true )
expect ( preloadedPackage . keymapActivated ) . toBe ( false )
expect ( preloadedPackage . settingsActivated ) . toBe ( false )
expect ( preloadedPackage . menusActivated ) . toBe ( false )
} )
} )
describe ( 'if the package was not preloaded' , ( ) => {
it ( 'adds the package path to the module cache' , ( ) => {
2019-02-22 10:55:17 +03:00
const availablePackage = atom . packages
. getAvailablePackages ( )
. find ( p => p . name === 'spell-check' )
2017-09-29 02:18:56 +03:00
availablePackage . isBundled = true
const metadata = atom . packages . loadPackageMetadata ( availablePackage )
atom . packages . loadAvailablePackage ( availablePackage )
2019-02-22 10:55:17 +03:00
expect ( ModuleCache . add ) . toHaveBeenCalledWith (
availablePackage . path ,
metadata
)
2017-09-29 02:18:56 +03:00
} )
} )
} )
describe ( 'preloading' , ( ) => {
it ( 'requires the main module, loads the config schema and activates keymaps, menus and settings without reactivating them during package activation' , ( ) => {
2019-02-22 10:55:17 +03:00
const availablePackage = atom . packages
. getAvailablePackages ( )
. find ( p => p . name === 'spell-check' )
2017-09-29 02:18:56 +03:00
availablePackage . isBundled = true
const metadata = atom . packages . loadPackageMetadata ( availablePackage )
2019-02-22 10:55:17 +03:00
expect (
atom . packages . preloadedPackages [ availablePackage . name ]
) . toBeUndefined ( )
2017-09-29 02:18:56 +03:00
expect ( atom . packages . isPackageLoaded ( availablePackage . name ) ) . toBe ( false )
atom . packages . packagesCache = { }
atom . packages . packagesCache [ availablePackage . name ] = {
main : path . join ( availablePackage . path , metadata . main ) ,
grammarPaths : [ ]
}
const preloadedPackage = atom . packages . preloadPackage (
availablePackage . name ,
{
2019-02-22 10:55:17 +03:00
rootDirPath : path . relative (
atom . packages . resourcePath ,
availablePackage . path
) ,
2017-09-29 02:18:56 +03:00
metadata
}
)
expect ( preloadedPackage . keymapActivated ) . toBe ( true )
expect ( preloadedPackage . settingsActivated ) . toBe ( true )
expect ( preloadedPackage . menusActivated ) . toBe ( true )
expect ( preloadedPackage . mainModule ) . toBeTruthy ( )
expect ( preloadedPackage . configSchemaRegisteredOnLoad ) . toBeTruthy ( )
spyOn ( atom . keymaps , 'add' )
spyOn ( atom . menu , 'add' )
spyOn ( atom . contextMenu , 'add' )
spyOn ( atom . config , 'setSchema' )
atom . packages . loadAvailablePackage ( availablePackage )
2019-02-22 10:55:17 +03:00
expect ( preloadedPackage . getMainModulePath ( ) ) . toBe (
path . join ( availablePackage . path , metadata . main )
)
2017-09-29 02:18:56 +03:00
atom . packages . activatePackage ( availablePackage . name )
expect ( atom . keymaps . add ) . not . toHaveBeenCalled ( )
expect ( atom . menu . add ) . not . toHaveBeenCalled ( )
expect ( atom . contextMenu . add ) . not . toHaveBeenCalled ( )
expect ( atom . config . setSchema ) . not . toHaveBeenCalled ( )
expect ( preloadedPackage . keymapActivated ) . toBe ( true )
expect ( preloadedPackage . settingsActivated ) . toBe ( true )
expect ( preloadedPackage . menusActivated ) . toBe ( true )
expect ( preloadedPackage . mainModule ) . toBeTruthy ( )
expect ( preloadedPackage . configSchemaRegisteredOnLoad ) . toBeTruthy ( )
} )
it ( 'deactivates disabled keymaps during package activation' , ( ) => {
2019-02-22 10:55:17 +03:00
const availablePackage = atom . packages
. getAvailablePackages ( )
. find ( p => p . name === 'spell-check' )
2017-09-29 02:18:56 +03:00
availablePackage . isBundled = true
const metadata = atom . packages . loadPackageMetadata ( availablePackage )
2019-02-22 10:55:17 +03:00
expect (
atom . packages . preloadedPackages [ availablePackage . name ]
) . toBeUndefined ( )
2017-09-29 02:18:56 +03:00
expect ( atom . packages . isPackageLoaded ( availablePackage . name ) ) . toBe ( false )
atom . packages . packagesCache = { }
atom . packages . packagesCache [ availablePackage . name ] = {
main : path . join ( availablePackage . path , metadata . main ) ,
grammarPaths : [ ]
}
const preloadedPackage = atom . packages . preloadPackage (
availablePackage . name ,
{
2019-02-22 10:55:17 +03:00
rootDirPath : path . relative (
atom . packages . resourcePath ,
availablePackage . path
) ,
2017-09-29 02:18:56 +03:00
metadata
}
)
expect ( preloadedPackage . keymapActivated ) . toBe ( true )
expect ( preloadedPackage . settingsActivated ) . toBe ( true )
expect ( preloadedPackage . menusActivated ) . toBe ( true )
atom . packages . loadAvailablePackage ( availablePackage )
2019-02-22 10:55:17 +03:00
atom . config . set ( 'core.packagesWithKeymapsDisabled' , [
availablePackage . name
] )
2017-09-29 02:18:56 +03:00
atom . packages . activatePackage ( availablePackage . name )
expect ( preloadedPackage . keymapActivated ) . toBe ( false )
expect ( preloadedPackage . settingsActivated ) . toBe ( true )
expect ( preloadedPackage . menusActivated ) . toBe ( true )
} )
} )
describe ( '::unloadPackage(name)' , ( ) => {
describe ( 'when the package is active' , ( ) => {
2017-09-29 03:04:46 +03:00
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 ( )
expect ( ( ) => atom . packages . unloadPackage ( pack . name ) ) . toThrow ( )
expect ( atom . packages . isPackageLoaded ( pack . name ) ) . toBeTruthy ( )
expect ( atom . packages . isPackageActive ( pack . name ) ) . toBeTruthy ( )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'when the package is not loaded' , ( ) => {
it ( 'throws an error' , ( ) => {
expect ( atom . packages . isPackageLoaded ( 'unloaded' ) ) . toBeFalsy ( )
expect ( ( ) => atom . packages . unloadPackage ( 'unloaded' ) ) . toThrow ( )
expect ( atom . packages . isPackageLoaded ( 'unloaded' ) ) . toBeFalsy ( )
} )
} )
describe ( 'when the package is loaded' , ( ) => {
it ( 'no longers reports it as being loaded' , ( ) => {
const pack = atom . packages . loadPackage ( 'package-with-main' )
expect ( atom . packages . isPackageLoaded ( pack . name ) ) . toBeTruthy ( )
atom . packages . unloadPackage ( pack . name )
expect ( atom . packages . isPackageLoaded ( pack . name ) ) . toBeFalsy ( )
} )
} )
it ( 'invokes ::onDidUnloadPackage listeners with the unloaded package' , ( ) => {
atom . packages . loadPackage ( 'package-with-main' )
let unloadedPackage
atom . packages . onDidUnloadPackage ( pack => {
unloadedPackage = pack
} )
atom . packages . unloadPackage ( 'package-with-main' )
expect ( unloadedPackage . name ) . toBe ( 'package-with-main' )
} )
} )
describe ( '::activatePackage(id)' , ( ) => {
describe ( 'when called multiple times' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'it only calls activate on the package once' , async ( ) => {
2017-09-29 02:18:56 +03:00
spyOn ( Package . prototype , 'activateNow' ) . andCallThrough ( )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-index' )
await atom . packages . activatePackage ( 'package-with-index' )
await atom . packages . activatePackage ( 'package-with-index' )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
expect ( Package . prototype . activateNow . callCount ) . toBe ( 1 )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'when the package has a main module' , ( ) => {
2017-11-09 03:28:11 +03:00
beforeEach ( ( ) => {
spyOn ( Package . prototype , 'requireMainModule' ) . andCallThrough ( )
} )
2017-09-29 02:18:56 +03:00
describe ( 'when the metadata specifies a main module path˜ ' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'requires the module at the specified path' , async ( ) => {
2017-09-29 02:18:56 +03:00
const mainModule = require ( './fixtures/packages/package-with-main/main-module' )
spyOn ( mainModule , 'activate' )
2017-09-29 03:04:46 +03:00
const pack = await atom . packages . activatePackage ( 'package-with-main' )
expect ( mainModule . activate ) . toHaveBeenCalled ( )
expect ( pack . mainModule ) . toBe ( mainModule )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'when the metadata does not specify a main module' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'requires index.coffee' , async ( ) => {
2017-09-29 02:18:56 +03:00
const indexModule = require ( './fixtures/packages/package-with-index/index' )
spyOn ( indexModule , 'activate' )
2017-09-29 03:04:46 +03:00
const pack = await atom . packages . activatePackage ( 'package-with-index' )
expect ( indexModule . activate ) . toHaveBeenCalled ( )
expect ( pack . mainModule ) . toBe ( indexModule )
2017-09-29 02:18:56 +03:00
} )
} )
2017-09-29 03:04:46 +03:00
it ( 'assigns config schema, including defaults when package contains a schema' , async ( ) => {
2019-02-22 10:55:17 +03:00
expect (
atom . config . get ( 'package-with-config-schema.numbers.one' )
) . toBeUndefined ( )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-config-schema' )
2019-02-22 10:55:17 +03:00
expect ( atom . config . get ( 'package-with-config-schema.numbers.one' ) ) . toBe (
1
)
expect ( atom . config . get ( 'package-with-config-schema.numbers.two' ) ) . toBe (
2
)
expect (
atom . config . set ( 'package-with-config-schema.numbers.one' , 'nope' )
) . toBe ( false )
expect (
atom . config . set ( 'package-with-config-schema.numbers.one' , '10' )
) . toBe ( true )
expect ( atom . config . get ( 'package-with-config-schema.numbers.one' ) ) . toBe (
10
)
2017-09-29 02:18:56 +03:00
} )
describe ( 'when the package metadata includes `activationCommands`' , ( ) => {
let mainModule , promise , workspaceCommandListener , registration
beforeEach ( ( ) => {
jasmine . attachToDOM ( atom . workspace . getElement ( ) )
mainModule = require ( './fixtures/packages/package-with-activation-commands/index' )
mainModule . activationCommandCallCount = 0
spyOn ( mainModule , 'activate' ) . andCallThrough ( )
2019-02-22 10:55:17 +03:00
workspaceCommandListener = jasmine . createSpy (
'workspaceCommandListener'
)
registration = atom . commands . add (
2019-05-15 23:21:15 +03:00
'atom-workspace' ,
2019-02-22 10:55:17 +03:00
'activation-command' ,
workspaceCommandListener
)
promise = atom . packages . activatePackage (
'package-with-activation-commands'
)
2017-09-29 02:18:56 +03:00
} )
afterEach ( ( ) => {
if ( registration ) {
registration . dispose ( )
}
mainModule = null
} )
2017-09-29 03:04:46 +03:00
it ( 'defers requiring/activating the main module until an activation event bubbles to the root view' , async ( ) => {
2017-09-29 02:18:56 +03:00
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 0 )
2019-02-22 10:55:17 +03:00
atom . workspace
. getElement ( )
. dispatchEvent (
new CustomEvent ( 'activation-command' , { bubbles : true } )
)
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await promise
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 1 )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( 'triggers the activation event on all handlers registered during activation' , async ( ) => {
await atom . workspace . open ( )
2019-02-22 10:55:17 +03:00
const editorElement = atom . workspace
. getActiveTextEditor ( )
. getElement ( )
const editorCommandListener = jasmine . createSpy (
'editorCommandListener'
)
atom . commands . add (
'atom-text-editor' ,
'activation-command' ,
editorCommandListener
)
2017-09-29 03:04:46 +03:00
atom . commands . dispatch ( editorElement , 'activation-command' )
expect ( mainModule . activate . callCount ) . toBe ( 1 )
expect ( mainModule . activationCommandCallCount ) . toBe ( 1 )
expect ( editorCommandListener . callCount ) . toBe ( 1 )
expect ( workspaceCommandListener . callCount ) . toBe ( 1 )
atom . commands . dispatch ( editorElement , 'activation-command' )
expect ( mainModule . activationCommandCallCount ) . toBe ( 2 )
expect ( editorCommandListener . callCount ) . toBe ( 2 )
expect ( workspaceCommandListener . callCount ) . toBe ( 2 )
expect ( mainModule . activate . callCount ) . toBe ( 1 )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( 'activates the package immediately when the events are empty' , async ( ) => {
2017-09-29 02:18:56 +03:00
mainModule = require ( './fixtures/packages/package-with-empty-activation-commands/index' )
spyOn ( mainModule , 'activate' ) . andCallThrough ( )
2019-02-22 10:55:17 +03:00
atom . packages . activatePackage (
'package-with-empty-activation-commands'
)
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
expect ( mainModule . activate . callCount ) . toBe ( 1 )
2017-09-29 02:18:56 +03:00
} )
it ( 'adds a notification when the activation commands are invalid' , ( ) => {
spyOn ( atom , 'inSpecMode' ) . andReturn ( false )
const addErrorHandler = jasmine . createSpy ( )
atom . notifications . onDidAddNotification ( addErrorHandler )
2019-02-22 10:55:17 +03:00
expect ( ( ) =>
atom . packages . activatePackage (
'package-with-invalid-activation-commands'
)
) . not . toThrow ( )
2017-09-29 02:18:56 +03:00
expect ( addErrorHandler . callCount ) . toBe ( 1 )
2019-02-22 10:55:17 +03:00
expect ( addErrorHandler . argsForCall [ 0 ] [ 0 ] . message ) . toContain (
'Failed to activate the package-with-invalid-activation-commands package'
)
expect ( addErrorHandler . argsForCall [ 0 ] [ 0 ] . options . packageName ) . toEqual (
'package-with-invalid-activation-commands'
)
2017-09-29 02:18:56 +03:00
} )
it ( 'adds a notification when the context menu is invalid' , ( ) => {
spyOn ( atom , 'inSpecMode' ) . andReturn ( false )
const addErrorHandler = jasmine . createSpy ( )
atom . notifications . onDidAddNotification ( addErrorHandler )
2019-02-22 10:55:17 +03:00
expect ( ( ) =>
atom . packages . activatePackage ( 'package-with-invalid-context-menu' )
) . not . toThrow ( )
2017-09-29 02:18:56 +03:00
expect ( addErrorHandler . callCount ) . toBe ( 1 )
2019-02-22 10:55:17 +03:00
expect ( addErrorHandler . argsForCall [ 0 ] [ 0 ] . message ) . toContain (
'Failed to activate the package-with-invalid-context-menu package'
)
expect ( addErrorHandler . argsForCall [ 0 ] [ 0 ] . options . packageName ) . toEqual (
'package-with-invalid-context-menu'
)
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( 'adds a notification when the grammar is invalid' , async ( ) => {
let notificationEvent
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await new Promise ( resolve => {
2019-02-22 10:55:17 +03:00
const subscription = atom . notifications . onDidAddNotification (
event => {
notificationEvent = event
subscription . dispose ( )
resolve ( )
}
)
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
atom . packages . activatePackage ( 'package-with-invalid-grammar' )
2017-09-29 02:18:56 +03:00
} )
2019-02-22 10:55:17 +03:00
expect ( notificationEvent . message ) . toContain (
'Failed to load a package-with-invalid-grammar package grammar'
)
expect ( notificationEvent . options . packageName ) . toEqual (
'package-with-invalid-grammar'
)
2017-09-29 03:04:46 +03:00
} )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
it ( 'adds a notification when the settings are invalid' , async ( ) => {
let notificationEvent
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await new Promise ( resolve => {
2019-02-22 10:55:17 +03:00
const subscription = atom . notifications . onDidAddNotification (
event => {
notificationEvent = event
subscription . dispose ( )
resolve ( )
}
)
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
atom . packages . activatePackage ( 'package-with-invalid-settings' )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
2019-02-22 10:55:17 +03:00
expect ( notificationEvent . message ) . toContain (
'Failed to load the package-with-invalid-settings package settings'
)
expect ( notificationEvent . options . packageName ) . toEqual (
'package-with-invalid-settings'
)
2017-09-29 02:18:56 +03:00
} )
2017-11-15 02:42:15 +03:00
} )
2017-11-09 03:28:11 +03:00
describe ( 'when the package metadata includes both activation commands and deserializers' , ( ) => {
let mainModule , promise , workspaceCommandListener , registration
beforeEach ( ( ) => {
jasmine . attachToDOM ( atom . workspace . getElement ( ) )
2017-12-04 22:44:12 +03:00
spyOn ( atom . packages , 'hasActivatedInitialPackages' ) . andReturn ( true )
2017-11-09 03:28:11 +03:00
mainModule = require ( './fixtures/packages/package-with-activation-commands-and-deserializers/index' )
mainModule . activationCommandCallCount = 0
spyOn ( mainModule , 'activate' ) . andCallThrough ( )
workspaceCommandListener = jasmine . createSpy ( 'workspaceCommandListener' )
registration = atom . commands . add ( '.workspace' , 'activation-command-2' , workspaceCommandListener )
promise = atom . packages . activatePackage ( 'package-with-activation-commands-and-deserializers' )
} )
afterEach ( ( ) => {
if ( registration ) {
registration . dispose ( )
}
mainModule = null
} )
it ( 'activates the package when a deserializer is called' , async ( ) => {
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 0 )
const state1 = { deserializer : 'Deserializer1' , a : 'b' }
2017-12-04 22:44:12 +03:00
expect ( atom . deserializers . deserialize ( state1 , atom ) ) . toEqual ( {
2017-11-09 03:28:11 +03:00
wasDeserializedBy : 'deserializeMethod1' ,
state : state1
} )
await promise
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 1 )
} )
it ( 'defers requiring/activating the main module until an activation event bubbles to the root view' , async ( ) => {
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 0 )
atom . workspace . getElement ( ) . dispatchEvent ( new CustomEvent ( 'activation-command-2' , { bubbles : true } ) )
await promise
expect ( mainModule . activate . callCount ) . toBe ( 1 )
expect ( mainModule . activationCommandCallCount ) . toBe ( 1 )
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 1 )
} )
} )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
describe ( 'when the package metadata includes `activationHooks`' , ( ) => {
let mainModule , promise
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
beforeEach ( ( ) => {
mainModule = require ( './fixtures/packages/package-with-activation-hooks/index' )
spyOn ( mainModule , 'activate' ) . andCallThrough ( )
} )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
it ( 'defers requiring/activating the main module until an triggering of an activation hook occurs' , async ( ) => {
promise = atom . packages . activatePackage ( 'package-with-activation-hooks' )
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 0 )
atom . packages . triggerActivationHook ( 'language-fictitious:grammar-used' )
atom . packages . triggerDeferredActivationHooks ( )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
await promise
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 1 )
} )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
it ( 'does not double register activation hooks when deactivating and reactivating' , async ( ) => {
promise = atom . packages . activatePackage ( 'package-with-activation-hooks' )
expect ( mainModule . activate . callCount ) . toBe ( 0 )
atom . packages . triggerActivationHook ( 'language-fictitious:grammar-used' )
atom . packages . triggerDeferredActivationHooks ( )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
await promise
expect ( mainModule . activate . callCount ) . toBe ( 1 )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
await atom . packages . deactivatePackage ( 'package-with-activation-hooks' )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
promise = atom . packages . activatePackage ( 'package-with-activation-hooks' )
atom . packages . triggerActivationHook ( 'language-fictitious:grammar-used' )
atom . packages . triggerDeferredActivationHooks ( )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
await promise
expect ( mainModule . activate . callCount ) . toBe ( 2 )
} )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
it ( 'activates the package immediately when activationHooks is empty' , async ( ) => {
mainModule = require ( './fixtures/packages/package-with-empty-activation-hooks/index' )
spyOn ( mainModule , 'activate' ) . andCallThrough ( )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 0 )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
await atom . packages . activatePackage ( 'package-with-empty-activation-hooks' )
expect ( mainModule . activate . callCount ) . toBe ( 1 )
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 1 )
} )
2017-09-29 02:18:56 +03:00
2017-11-15 03:16:00 +03:00
it ( 'activates the package immediately if the activation hook had already been triggered' , async ( ) => {
atom . packages . triggerActivationHook ( 'language-fictitious:grammar-used' )
atom . packages . triggerDeferredActivationHooks ( )
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 0 )
2017-09-29 02:18:56 +03:00
2019-05-15 23:21:15 +03:00
await atom . packages . activatePackage (
'package-with-activation-hooks'
)
expect ( mainModule . activate . callCount ) . toBe ( 1 )
2017-11-15 03:16:00 +03:00
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 1 )
} )
2017-09-29 02:18:56 +03:00
} )
2017-11-15 03:16:00 +03:00
describe ( 'when the package metadata includes `workspaceOpeners`' , ( ) => {
let mainModule , promise
2017-11-15 02:53:56 +03:00
2017-11-15 03:16:00 +03:00
beforeEach ( ( ) => {
mainModule = require ( './fixtures/packages/package-with-workspace-openers/index' )
spyOn ( mainModule , 'activate' ) . andCallThrough ( )
} )
2017-11-15 02:53:56 +03:00
2017-11-15 03:16:00 +03:00
it ( 'defers requiring/activating the main module until a registered opener is called' , async ( ) => {
promise = atom . packages . activatePackage ( 'package-with-workspace-openers' )
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 0 )
atom . workspace . open ( 'atom://fictitious' )
2017-11-15 02:53:56 +03:00
2017-11-15 03:16:00 +03:00
await promise
expect ( Package . prototype . requireMainModule . callCount ) . toBe ( 1 )
expect ( mainModule . openerCount ) . toBe ( 1 )
} )
2017-11-15 02:53:56 +03:00
2017-11-15 03:16:00 +03:00
it ( 'activates the package immediately when the events are empty' , async ( ) => {
mainModule = require ( './fixtures/packages/package-with-empty-workspace-openers/index' )
spyOn ( mainModule , 'activate' ) . andCallThrough ( )
2017-11-15 02:53:56 +03:00
2017-11-15 03:16:00 +03:00
atom . packages . activatePackage ( 'package-with-empty-workspace-openers' )
2017-11-15 02:53:56 +03:00
2017-11-15 03:16:00 +03:00
expect ( mainModule . activate . callCount ) . toBe ( 1 )
} )
2017-11-15 02:53:56 +03:00
} )
} )
2017-09-29 02:18:56 +03:00
describe ( 'when the package has no main module' , ( ) => {
it ( 'does not throw an exception' , ( ) => {
spyOn ( console , 'error' )
spyOn ( console , 'warn' ) . andCallThrough ( )
2019-02-22 10:55:17 +03:00
expect ( ( ) =>
atom . packages . activatePackage ( 'package-without-module' )
) . not . toThrow ( )
2017-09-29 02:18:56 +03:00
expect ( console . error ) . not . toHaveBeenCalled ( )
expect ( console . warn ) . not . toHaveBeenCalled ( )
} )
} )
describe ( 'when the package does not export an activate function' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'activates the package and does not throw an exception or log a warning' , async ( ) => {
2017-09-29 02:18:56 +03:00
spyOn ( console , 'warn' )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-no-activate' )
expect ( console . warn ) . not . toHaveBeenCalled ( )
2017-09-29 02:18:56 +03:00
} )
} )
2017-09-29 03:04:46 +03:00
it ( "passes the activate method the package's previously serialized state if it exists" , async ( ) => {
2019-02-22 10:55:17 +03:00
const pack = await atom . packages . activatePackage (
'package-with-serialization'
)
2017-09-29 03:04:46 +03:00
expect ( pack . mainModule . someNumber ) . not . toBe ( 77 )
pack . mainModule . someNumber = 77
atom . packages . serializePackage ( 'package-with-serialization' )
await atom . packages . deactivatePackage ( 'package-with-serialization' )
spyOn ( pack . mainModule , 'activate' ) . andCallThrough ( )
await atom . packages . activatePackage ( 'package-with-serialization' )
2019-02-22 10:55:17 +03:00
expect ( pack . mainModule . activate ) . toHaveBeenCalledWith ( { someNumber : 77 } )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( 'invokes ::onDidActivatePackage listeners with the activated package' , async ( ) => {
2017-09-29 02:18:56 +03:00
let activatedPackage
atom . packages . onDidActivatePackage ( pack => {
activatedPackage = pack
} )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-main' )
expect ( activatedPackage . name ) . toBe ( 'package-with-main' )
2017-09-29 02:18:56 +03:00
} )
describe ( "when the package's main module throws an error on load" , ( ) => {
it ( 'adds a notification instead of throwing an exception' , ( ) => {
spyOn ( atom , 'inSpecMode' ) . andReturn ( false )
atom . config . set ( 'core.disabledPackages' , [ ] )
const addErrorHandler = jasmine . createSpy ( )
atom . notifications . onDidAddNotification ( addErrorHandler )
2019-02-22 10:55:17 +03:00
expect ( ( ) =>
atom . packages . activatePackage ( 'package-that-throws-an-exception' )
) . not . toThrow ( )
2017-09-29 02:18:56 +03:00
expect ( addErrorHandler . callCount ) . toBe ( 1 )
2019-02-22 10:55:17 +03:00
expect ( addErrorHandler . argsForCall [ 0 ] [ 0 ] . message ) . toContain (
'Failed to load the package-that-throws-an-exception package'
)
expect ( addErrorHandler . argsForCall [ 0 ] [ 0 ] . options . packageName ) . toEqual (
'package-that-throws-an-exception'
)
2017-09-29 02:18:56 +03:00
} )
it ( 're-throws the exception in test mode' , ( ) => {
atom . config . set ( 'core.disabledPackages' , [ ] )
2019-02-22 10:55:17 +03:00
expect ( ( ) =>
atom . packages . activatePackage ( 'package-that-throws-an-exception' )
) . toThrow ( 'This package throws an exception' )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'when the package is not found' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'rejects the promise' , async ( ) => {
2017-09-29 02:18:56 +03:00
spyOn ( console , 'warn' )
2017-09-29 03:04:46 +03:00
atom . config . set ( 'core.disabledPackages' , [ ] )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
try {
await atom . packages . activatePackage ( 'this-doesnt-exist' )
expect ( 'Error to be thrown' ) . toBe ( '' )
} catch ( error ) {
2017-09-29 02:18:56 +03:00
expect ( console . warn . callCount ) . toBe ( 1 )
2019-02-22 10:55:17 +03:00
expect ( error . message ) . toContain (
"Failed to load package 'this-doesnt-exist'"
)
2017-09-29 03:04:46 +03:00
}
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'keymap loading' , ( ) => {
describe ( "when the metadata does not contain a 'keymaps' manifest" , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'loads all the .cson/.json files in the keymaps directory' , async ( ) => {
2017-09-29 02:18:56 +03:00
const element1 = createTestElement ( 'test-1' )
const element2 = createTestElement ( 'test-2' )
const element3 = createTestElement ( 'test-3' )
2019-02-22 10:55:17 +03:00
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element1
} )
) . toHaveLength ( 0 )
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element2
} )
) . toHaveLength ( 0 )
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element3
} )
) . toHaveLength ( 0 )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-keymaps' )
2019-02-22 10:55:17 +03:00
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element1
} ) [ 0 ] . command
) . toBe ( 'test-1' )
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element2
} ) [ 0 ] . command
) . toBe ( 'test-2' )
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element3
} )
) . toHaveLength ( 0 )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( "when the metadata contains a 'keymaps' manifest" , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'loads only the keymaps specified by the manifest, in the specified order' , async ( ) => {
2017-09-29 02:18:56 +03:00
const element1 = createTestElement ( 'test-1' )
const element3 = createTestElement ( 'test-3' )
2019-02-22 10:55:17 +03:00
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element1
} )
) . toHaveLength ( 0 )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-keymaps-manifest' )
2019-02-22 10:55:17 +03:00
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element1
} ) [ 0 ] . command
) . toBe ( 'keymap-1' )
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-n' ,
target : element1
} ) [ 0 ] . command
) . toBe ( 'keymap-2' )
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-y' ,
target : element3
} )
) . toHaveLength ( 0 )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'when the keymap file is empty' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'does not throw an error on activation' , async ( ) => {
await atom . packages . activatePackage ( 'package-with-empty-keymap' )
2019-02-22 10:55:17 +03:00
expect (
atom . packages . isPackageActive ( 'package-with-empty-keymap' )
) . toBe ( true )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( "when the package's keymaps have been disabled" , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'does not add the keymaps' , async ( ) => {
2017-09-29 02:18:56 +03:00
const element1 = createTestElement ( 'test-1' )
2019-02-22 10:55:17 +03:00
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element1
} )
) . toHaveLength ( 0 )
2017-09-29 02:18:56 +03:00
2019-02-22 10:55:17 +03:00
atom . config . set ( 'core.packagesWithKeymapsDisabled' , [
'package-with-keymaps-manifest'
] )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-keymaps-manifest' )
2019-02-22 10:55:17 +03:00
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element1
} )
) . toHaveLength ( 0 )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'when setting core.packagesWithKeymapsDisabled' , ( ) => {
it ( "ignores package names in the array that aren't loaded" , ( ) => {
atom . packages . observePackagesWithKeymapsDisabled ( )
2019-02-22 10:55:17 +03:00
expect ( ( ) =>
atom . config . set ( 'core.packagesWithKeymapsDisabled' , [
'package-does-not-exist'
] )
) . not . toThrow ( )
expect ( ( ) =>
atom . config . set ( 'core.packagesWithKeymapsDisabled' , [ ] )
) . not . toThrow ( )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( "when the package's keymaps are disabled and re-enabled after it is activated" , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'removes and re-adds the keymaps' , async ( ) => {
2017-09-29 02:18:56 +03:00
const element1 = createTestElement ( 'test-1' )
atom . packages . observePackagesWithKeymapsDisabled ( )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-keymaps-manifest' )
2017-09-29 02:18:56 +03:00
2019-02-22 10:55:17 +03:00
atom . config . set ( 'core.packagesWithKeymapsDisabled' , [
'package-with-keymaps-manifest'
] )
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element1
} )
) . toHaveLength ( 0 )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
atom . config . set ( 'core.packagesWithKeymapsDisabled' , [ ] )
2019-02-22 10:55:17 +03:00
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : element1
} ) [ 0 ] . command
) . toBe ( 'keymap-1' )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'when the package is de-activated and re-activated' , ( ) => {
let element , events , userKeymapPath
beforeEach ( ( ) => {
userKeymapPath = path . join ( temp . mkdirSync ( ) , 'user-keymaps.cson' )
spyOn ( atom . keymaps , 'getUserKeymapPath' ) . andReturn ( userKeymapPath )
element = createTestElement ( 'test-1' )
jasmine . attachToDOM ( element )
events = [ ]
element . addEventListener ( 'user-command' , e => events . push ( e ) )
element . addEventListener ( 'test-1' , e => events . push ( e ) )
} )
afterEach ( ( ) => {
element . remove ( )
// Avoid leaking user keymap subscription
atom . keymaps . watchSubscriptions [ userKeymapPath ] . dispose ( )
delete atom . keymaps . watchSubscriptions [ userKeymapPath ]
temp . cleanupSync ( )
} )
2017-09-29 03:04:46 +03:00
it ( "doesn't override user-defined keymaps" , async ( ) => {
2019-02-22 10:55:17 +03:00
fs . writeFileSync (
userKeymapPath ,
` ".test-1": {"ctrl-z": "user-command"} `
)
2017-09-29 02:18:56 +03:00
atom . keymaps . loadUserKeymap ( )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-keymaps' )
2019-02-22 10:55:17 +03:00
atom . keymaps . handleKeyboardEvent (
buildKeydownEvent ( 'z' , { ctrl : true , target : element } )
)
2017-09-29 03:04:46 +03:00
expect ( events . length ) . toBe ( 1 )
expect ( events [ 0 ] . type ) . toBe ( 'user-command' )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . deactivatePackage ( 'package-with-keymaps' )
await atom . packages . activatePackage ( 'package-with-keymaps' )
2019-02-22 10:55:17 +03:00
atom . keymaps . handleKeyboardEvent (
buildKeydownEvent ( 'z' , { ctrl : true , target : element } )
)
2017-09-29 03:04:46 +03:00
expect ( events . length ) . toBe ( 2 )
expect ( events [ 1 ] . type ) . toBe ( 'user-command' )
2017-09-29 02:18:56 +03:00
} )
} )
} )
describe ( 'menu loading' , ( ) => {
beforeEach ( ( ) => {
atom . contextMenu . definitions = [ ]
atom . menu . template = [ ]
} )
describe ( "when the metadata does not contain a 'menus' manifest" , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'loads all the .cson/.json files in the menus directory' , async ( ) => {
2017-09-29 02:18:56 +03:00
const element = createTestElement ( 'test-1' )
expect ( atom . contextMenu . templateForElement ( element ) ) . toEqual ( [ ] )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-menus' )
expect ( atom . menu . template . length ) . toBe ( 2 )
expect ( atom . menu . template [ 0 ] . label ) . toBe ( 'Second to Last' )
expect ( atom . menu . template [ 1 ] . label ) . toBe ( 'Last' )
2019-02-22 10:55:17 +03:00
expect ( atom . contextMenu . templateForElement ( element ) [ 0 ] . label ) . toBe (
'Menu item 1'
)
expect ( atom . contextMenu . templateForElement ( element ) [ 1 ] . label ) . toBe (
'Menu item 2'
)
expect ( atom . contextMenu . templateForElement ( element ) [ 2 ] . label ) . toBe (
'Menu item 3'
)
2017-09-29 02:18:56 +03:00
} )
} )
describe ( "when the metadata contains a 'menus' manifest" , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'loads only the menus specified by the manifest, in the specified order' , async ( ) => {
2017-09-29 02:18:56 +03:00
const element = createTestElement ( 'test-1' )
expect ( atom . contextMenu . templateForElement ( element ) ) . toEqual ( [ ] )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-menus-manifest' )
expect ( atom . menu . template [ 0 ] . label ) . toBe ( 'Second to Last' )
expect ( atom . menu . template [ 1 ] . label ) . toBe ( 'Last' )
2019-02-22 10:55:17 +03:00
expect ( atom . contextMenu . templateForElement ( element ) [ 0 ] . label ) . toBe (
'Menu item 2'
)
expect ( atom . contextMenu . templateForElement ( element ) [ 1 ] . label ) . toBe (
'Menu item 1'
)
expect (
atom . contextMenu . templateForElement ( element ) [ 2 ]
) . toBeUndefined ( )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'when the menu file is empty' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'does not throw an error on activation' , async ( ) => {
await atom . packages . activatePackage ( 'package-with-empty-menu' )
2019-02-22 10:55:17 +03:00
expect ( atom . packages . isPackageActive ( 'package-with-empty-menu' ) ) . toBe (
true
)
2017-09-29 02:18:56 +03:00
} )
} )
} )
describe ( 'stylesheet loading' , ( ) => {
describe ( "when the metadata contains a 'styleSheets' manifest" , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'loads style sheets from the styles directory as specified by the manifest' , async ( ) => {
2019-02-22 10:55:17 +03:00
const one = require . resolve (
'./fixtures/packages/package-with-style-sheets-manifest/styles/1.css'
)
const two = require . resolve (
'./fixtures/packages/package-with-style-sheets-manifest/styles/2.less'
)
const three = require . resolve (
'./fixtures/packages/package-with-style-sheets-manifest/styles/3.css'
)
2017-09-29 02:18:56 +03:00
expect ( atom . themes . stylesheetElementForId ( one ) ) . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( two ) ) . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( three ) ) . toBeNull ( )
2019-02-22 10:55:17 +03:00
await atom . packages . activatePackage (
'package-with-style-sheets-manifest'
)
2017-09-29 03:04:46 +03:00
expect ( atom . themes . stylesheetElementForId ( one ) ) . not . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( two ) ) . not . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( three ) ) . toBeNull ( )
2019-02-22 10:55:17 +03:00
expect (
getComputedStyle ( document . querySelector ( '#jasmine-content' ) )
. fontSize
) . toBe ( '1px' )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( "when the metadata does not contain a 'styleSheets' manifest" , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'loads all style sheets from the styles directory' , async ( ) => {
2019-02-22 10:55:17 +03:00
const one = require . resolve (
'./fixtures/packages/package-with-styles/styles/1.css'
)
const two = require . resolve (
'./fixtures/packages/package-with-styles/styles/2.less'
)
const three = require . resolve (
'./fixtures/packages/package-with-styles/styles/3.test-context.css'
)
const four = require . resolve (
'./fixtures/packages/package-with-styles/styles/4.css'
)
2017-09-29 02:18:56 +03:00
expect ( atom . themes . stylesheetElementForId ( one ) ) . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( two ) ) . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( three ) ) . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( four ) ) . toBeNull ( )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-styles' )
expect ( atom . themes . stylesheetElementForId ( one ) ) . not . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( two ) ) . not . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( three ) ) . not . toBeNull ( )
expect ( atom . themes . stylesheetElementForId ( four ) ) . not . toBeNull ( )
2019-02-22 10:55:17 +03:00
expect (
getComputedStyle ( document . querySelector ( '#jasmine-content' ) )
. fontSize
) . toBe ( '3px' )
2017-09-29 02:18:56 +03:00
} )
} )
2017-09-29 03:04:46 +03:00
it ( "assigns the stylesheet's context based on the filename" , async ( ) => {
await atom . packages . activatePackage ( 'package-with-styles' )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
let count = 0
for ( let styleElement of atom . styles . getStyleElements ( ) ) {
if ( styleElement . sourcePath . match ( /1.css/ ) ) {
expect ( styleElement . context ) . toBe ( undefined )
count ++
}
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
if ( styleElement . sourcePath . match ( /2.less/ ) ) {
expect ( styleElement . context ) . toBe ( undefined )
count ++
}
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
if ( styleElement . sourcePath . match ( /3.test-context.css/ ) ) {
expect ( styleElement . context ) . toBe ( 'test-context' )
count ++
}
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
if ( styleElement . sourcePath . match ( /4.css/ ) ) {
expect ( styleElement . context ) . toBe ( undefined )
count ++
2017-09-29 02:18:56 +03:00
}
2017-09-29 03:04:46 +03:00
}
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
expect ( count ) . toBe ( 4 )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( 'grammar loading' , ( ) => {
2017-09-29 03:04:46 +03:00
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' )
2017-09-29 02:18:56 +03:00
} )
2017-11-30 04:22:35 +03:00
it ( 'loads any tree-sitter grammars defined in the package' , async ( ) => {
2018-06-05 02:35:32 +03:00
atom . config . set ( 'core.useTreeSitterParsers' , true )
2017-11-30 04:22:35 +03:00
await atom . packages . activatePackage ( 'package-with-tree-sitter-grammar' )
const grammar = atom . grammars . selectGrammar ( 'test.somelang' )
expect ( grammar . name ) . toBe ( 'Some Language' )
expect ( grammar . languageModule . isFakeTreeSitterParser ) . toBe ( true )
} )
2017-09-29 02:18:56 +03:00
} )
describe ( 'scoped-property loading' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'loads the scoped properties' , async ( ) => {
await atom . packages . activatePackage ( 'package-with-settings' )
2019-02-22 10:55:17 +03:00
expect (
atom . config . get ( 'editor.increaseIndentPattern' , {
scope : [ '.source.omg' ]
} )
) . toBe ( '^a' )
2017-09-29 02:18:56 +03:00
} )
} )
2019-02-22 10:55:17 +03:00
describe ( 'URI handler registration' , ( ) => {
2017-10-18 01:23:10 +03:00
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' )
2017-10-03 23:20:48 +03:00
spyOn ( atom . packages , 'hasLoadedInitialPackages' ) . andReturn ( true )
2019-02-22 10:55:17 +03:00
const activationPromise = atom . packages . activatePackage (
'package-with-uri-handler'
)
2017-10-18 01:23:10 +03:00
atom . dispatchURIMessage ( uri )
2017-10-03 23:20:48 +03:00
await activationPromise
2017-10-18 01:23:10 +03:00
expect ( mod . handleURI ) . toHaveBeenCalledWith ( url . parse ( uri , true ) , uri )
2017-10-03 23:20:48 +03:00
} )
} )
2017-09-29 02:18:56 +03:00
describe ( 'service registration' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( "registers the package's provided and consumed services" , async ( ) => {
2017-09-29 02:18:56 +03:00
const consumerModule = require ( './fixtures/packages/package-with-consumed-services' )
2017-09-29 03:04:46 +03:00
2017-09-29 02:18:56 +03:00
let firstServiceV3Disposed = false
let firstServiceV4Disposed = false
let secondServiceDisposed = false
2019-02-22 10:55:17 +03:00
spyOn ( consumerModule , 'consumeFirstServiceV3' ) . andReturn (
new Disposable ( ( ) => {
firstServiceV3Disposed = true
} )
)
spyOn ( consumerModule , 'consumeFirstServiceV4' ) . andReturn (
new Disposable ( ( ) => {
firstServiceV4Disposed = true
} )
)
spyOn ( consumerModule , 'consumeSecondService' ) . andReturn (
new Disposable ( ( ) => {
secondServiceDisposed = true
} )
)
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-consumed-services' )
await atom . packages . activatePackage ( 'package-with-provided-services' )
expect ( consumerModule . consumeFirstServiceV3 . callCount ) . toBe ( 1 )
2019-02-22 10:55:17 +03:00
expect ( consumerModule . consumeFirstServiceV3 ) . toHaveBeenCalledWith (
'first-service-v3'
)
expect ( consumerModule . consumeFirstServiceV4 ) . toHaveBeenCalledWith (
'first-service-v4'
)
expect ( consumerModule . consumeSecondService ) . toHaveBeenCalledWith (
'second-service'
)
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
consumerModule . consumeFirstServiceV3 . reset ( )
consumerModule . consumeFirstServiceV4 . reset ( )
consumerModule . consumeSecondService . reset ( )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . deactivatePackage ( 'package-with-provided-services' )
expect ( firstServiceV3Disposed ) . toBe ( true )
expect ( firstServiceV4Disposed ) . toBe ( true )
expect ( secondServiceDisposed ) . toBe ( true )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . deactivatePackage ( 'package-with-consumed-services' )
await atom . packages . activatePackage ( 'package-with-provided-services' )
expect ( consumerModule . consumeFirstServiceV3 ) . not . toHaveBeenCalled ( )
expect ( consumerModule . consumeFirstServiceV4 ) . not . toHaveBeenCalled ( )
expect ( consumerModule . consumeSecondService ) . not . toHaveBeenCalled ( )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( 'ignores provided and consumed services that do not exist' , async ( ) => {
2017-09-29 02:18:56 +03:00
const addErrorHandler = jasmine . createSpy ( )
atom . notifications . onDidAddNotification ( addErrorHandler )
2019-02-22 10:55:17 +03:00
await atom . packages . activatePackage (
'package-with-missing-consumed-services'
)
await atom . packages . activatePackage (
'package-with-missing-provided-services'
)
expect (
atom . packages . isPackageActive (
'package-with-missing-consumed-services'
)
) . toBe ( true )
expect (
atom . packages . isPackageActive (
'package-with-missing-provided-services'
)
) . toBe ( true )
2017-09-29 03:04:46 +03:00
expect ( addErrorHandler . callCount ) . toBe ( 0 )
2017-09-29 02:18:56 +03:00
} )
} )
} )
describe ( '::serialize' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'does not serialize packages that threw an error during activation' , async ( ) => {
2017-09-29 02:18:56 +03:00
spyOn ( atom , 'inSpecMode' ) . andReturn ( false )
spyOn ( console , 'warn' )
2019-02-22 10:55:17 +03:00
const badPack = await atom . packages . activatePackage (
'package-that-throws-on-activate'
)
2017-09-29 03:04:46 +03:00
spyOn ( badPack . mainModule , 'serialize' ) . andCallThrough ( )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
atom . packages . serialize ( )
expect ( badPack . mainModule . serialize ) . not . toHaveBeenCalled ( )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( "absorbs exceptions that are thrown by the package module's serialize method" , async ( ) => {
2017-09-29 02:18:56 +03:00
spyOn ( console , 'error' )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-with-serialize-error' )
await atom . packages . activatePackage ( 'package-with-serialization' )
atom . packages . serialize ( )
2019-02-22 10:55:17 +03:00
expect (
atom . packages . packageStates [ 'package-with-serialize-error' ]
) . toBeUndefined ( )
expect ( atom . packages . packageStates [ 'package-with-serialization' ] ) . toEqual (
{ someNumber : 1 }
)
2017-09-29 03:04:46 +03:00
expect ( console . error ) . toHaveBeenCalled ( )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( '::deactivatePackages()' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'deactivates all packages but does not serialize them' , async ( ) => {
2019-02-22 10:55:17 +03:00
const pack1 = await atom . packages . activatePackage (
'package-with-deactivate'
)
const pack2 = await atom . packages . activatePackage (
'package-with-serialization'
)
2017-09-29 03:04:46 +03:00
spyOn ( pack1 . mainModule , 'deactivate' )
spyOn ( pack2 . mainModule , 'serialize' )
await atom . packages . deactivatePackages ( )
expect ( pack1 . mainModule . deactivate ) . toHaveBeenCalled ( )
expect ( pack2 . mainModule . serialize ) . not . toHaveBeenCalled ( )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( '::deactivatePackage(id)' , ( ) => {
afterEach ( ( ) => atom . packages . unloadPackages ( ) )
2017-09-29 03:04:46 +03:00
it ( "calls `deactivate` on the package's main module if activate was successful" , async ( ) => {
2017-09-29 02:18:56 +03:00
spyOn ( atom , 'inSpecMode' ) . andReturn ( false )
2019-02-22 10:55:17 +03:00
const pack = await atom . packages . activatePackage (
'package-with-deactivate'
)
expect (
atom . packages . isPackageActive ( 'package-with-deactivate' )
) . toBeTruthy ( )
2017-09-29 03:04:46 +03:00
spyOn ( pack . mainModule , 'deactivate' ) . andCallThrough ( )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . deactivatePackage ( 'package-with-deactivate' )
expect ( pack . mainModule . deactivate ) . toHaveBeenCalled ( )
expect ( atom . packages . isPackageActive ( 'package-with-module' ) ) . toBeFalsy ( )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
spyOn ( console , 'warn' )
2019-02-22 10:55:17 +03:00
const badPack = await atom . packages . activatePackage (
'package-that-throws-on-activate'
)
expect (
atom . packages . isPackageActive ( 'package-that-throws-on-activate' )
) . toBeTruthy ( )
2017-09-29 03:04:46 +03:00
spyOn ( badPack . mainModule , 'deactivate' ) . andCallThrough ( )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . deactivatePackage ( 'package-that-throws-on-activate' )
expect ( badPack . mainModule . deactivate ) . not . toHaveBeenCalled ( )
2019-02-22 10:55:17 +03:00
expect (
atom . packages . isPackageActive ( 'package-that-throws-on-activate' )
) . toBeFalsy ( )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( "absorbs exceptions that are thrown by the package module's deactivate method" , async ( ) => {
2017-09-29 02:18:56 +03:00
spyOn ( console , 'error' )
2017-09-29 03:04:46 +03:00
await atom . packages . activatePackage ( 'package-that-throws-on-deactivate' )
await atom . packages . deactivatePackage ( 'package-that-throws-on-deactivate' )
expect ( console . error ) . toHaveBeenCalled ( )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
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' )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( "removes the package's keymaps" , async ( ) => {
await atom . packages . activatePackage ( 'package-with-keymaps' )
await atom . packages . deactivatePackage ( 'package-with-keymaps' )
2019-02-22 10:55:17 +03:00
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : createTestElement ( 'test-1' )
} )
) . toHaveLength ( 0 )
expect (
atom . keymaps . findKeyBindings ( {
keystrokes : 'ctrl-z' ,
target : createTestElement ( 'test-2' )
} )
) . toHaveLength ( 0 )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( "removes the package's stylesheets" , async ( ) => {
await atom . packages . activatePackage ( 'package-with-styles' )
await atom . packages . deactivatePackage ( 'package-with-styles' )
2017-09-29 02:18:56 +03:00
2019-02-22 10:55:17 +03:00
const one = require . resolve (
'./fixtures/packages/package-with-style-sheets-manifest/styles/1.css'
)
const two = require . resolve (
'./fixtures/packages/package-with-style-sheets-manifest/styles/2.less'
)
const three = require . resolve (
'./fixtures/packages/package-with-style-sheets-manifest/styles/3.css'
)
2017-09-29 03:04:46 +03:00
expect ( atom . themes . stylesheetElementForId ( one ) ) . not . toExist ( )
expect ( atom . themes . stylesheetElementForId ( two ) ) . not . toExist ( )
expect ( atom . themes . stylesheetElementForId ( three ) ) . not . toExist ( )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( "removes the package's scoped-properties" , async ( ) => {
await atom . packages . activatePackage ( 'package-with-settings' )
2019-02-22 10:55:17 +03:00
expect (
atom . config . get ( 'editor.increaseIndentPattern' , {
scope : [ '.source.omg' ]
} )
) . toBe ( '^a' )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await atom . packages . deactivatePackage ( 'package-with-settings' )
2019-02-22 10:55:17 +03:00
expect (
atom . config . get ( 'editor.increaseIndentPattern' , {
scope : [ '.source.omg' ]
} )
) . toBeUndefined ( )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( 'invokes ::onDidDeactivatePackage listeners with the deactivated package' , async ( ) => {
await atom . packages . activatePackage ( 'package-with-main' )
2017-09-29 02:18:56 +03:00
let deactivatedPackage
2017-09-29 03:04:46 +03:00
atom . packages . onDidDeactivatePackage ( pack => {
deactivatedPackage = pack
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
await atom . packages . deactivatePackage ( 'package-with-main' )
expect ( deactivatedPackage . name ) . toBe ( 'package-with-main' )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( '::activate()' , ( ) => {
beforeEach ( ( ) => {
spyOn ( atom , 'inSpecMode' ) . andReturn ( false )
jasmine . snapshotDeprecations ( )
spyOn ( console , 'warn' )
atom . packages . loadPackages ( )
const loadedPackages = atom . packages . getLoadedPackages ( )
expect ( loadedPackages . length ) . toBeGreaterThan ( 0 )
} )
2017-09-29 03:04:46 +03:00
afterEach ( async ( ) => {
await atom . packages . deactivatePackages ( )
atom . packages . unloadPackages ( )
jasmine . restoreDeprecationsSnapshot ( )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( 'sets hasActivatedInitialPackages' , async ( ) => {
2017-09-29 02:18:56 +03:00
spyOn ( atom . styles , 'getUserStyleSheetPath' ) . andReturn ( null )
spyOn ( atom . packages , 'activatePackages' )
expect ( atom . packages . hasActivatedInitialPackages ( ) ) . toBe ( false )
2017-09-29 03:04:46 +03:00
await atom . packages . activate ( )
expect ( atom . packages . hasActivatedInitialPackages ( ) ) . toBe ( true )
2017-09-29 02:18:56 +03:00
} )
it ( 'activates all the packages, and none of the themes' , ( ) => {
const packageActivator = spyOn ( atom . packages , 'activatePackages' )
const themeActivator = spyOn ( atom . themes , 'activatePackages' )
atom . packages . activate ( )
expect ( packageActivator ) . toHaveBeenCalled ( )
expect ( themeActivator ) . toHaveBeenCalled ( )
const packages = packageActivator . mostRecentCall . args [ 0 ]
2019-02-22 10:55:17 +03:00
for ( let pack of packages ) {
expect ( [ 'atom' , 'textmate' ] ) . toContain ( pack . getType ( ) )
}
2017-09-29 02:18:56 +03:00
const themes = themeActivator . mostRecentCall . args [ 0 ]
2019-02-22 10:55:17 +03:00
themes . map ( theme => expect ( [ 'theme' ] ) . toContain ( theme . getType ( ) ) )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( 'calls callbacks registered with ::onDidActivateInitialPackages' , async ( ) => {
2017-09-29 02:18:56 +03:00
const package1 = atom . packages . loadPackage ( 'package-with-main' )
const package2 = atom . packages . loadPackage ( 'package-with-index' )
2019-02-22 10:55:17 +03:00
const package3 = atom . packages . loadPackage (
'package-with-activation-commands'
)
spyOn ( atom . packages , 'getLoadedPackages' ) . andReturn ( [
package1 ,
package2 ,
package3
] )
2017-09-29 02:18:56 +03:00
spyOn ( atom . themes , 'activatePackages' )
atom . packages . activate ( )
2019-02-22 10:55:17 +03:00
await new Promise ( resolve =>
atom . packages . onDidActivateInitialPackages ( resolve )
)
2017-09-29 03:04:46 +03:00
jasmine . unspy ( atom . packages , 'getLoadedPackages' )
expect ( atom . packages . getActivePackages ( ) . includes ( package1 ) ) . toBe ( true )
expect ( atom . packages . getActivePackages ( ) . includes ( package2 ) ) . toBe ( true )
expect ( atom . packages . getActivePackages ( ) . includes ( package3 ) ) . toBe ( false )
2017-09-29 02:18:56 +03:00
} )
} )
describe ( '::enablePackage(id) and ::disablePackage(id)' , ( ) => {
describe ( 'with packages' , ( ) => {
2017-09-29 03:04:46 +03:00
it ( 'enables a disabled package' , async ( ) => {
2017-09-29 02:18:56 +03:00
const packageName = 'package-with-main'
atom . config . pushAtKeyPath ( 'core.disabledPackages' , packageName )
atom . packages . observeDisabledPackages ( )
expect ( atom . config . get ( 'core.disabledPackages' ) ) . toContain ( packageName )
const pack = atom . packages . enablePackage ( packageName )
2019-02-22 10:55:17 +03:00
await new Promise ( resolve =>
atom . packages . onDidActivatePackage ( resolve )
)
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
expect ( atom . packages . getLoadedPackages ( ) ) . toContain ( pack )
expect ( atom . packages . getActivePackages ( ) ) . toContain ( pack )
2019-02-22 10:55:17 +03:00
expect ( atom . config . get ( 'core.disabledPackages' ) ) . not . toContain (
packageName
)
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
it ( 'disables an enabled package' , async ( ) => {
2017-09-29 02:18:56 +03:00
const packageName = 'package-with-main'
2017-09-29 03:04:46 +03:00
const pack = await atom . packages . activatePackage ( packageName )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
atom . packages . observeDisabledPackages ( )
2019-02-22 10:55:17 +03:00
expect ( atom . config . get ( 'core.disabledPackages' ) ) . not . toContain (
packageName
)
2017-09-29 03:04:46 +03:00
await new Promise ( resolve => {
atom . packages . onDidDeactivatePackage ( resolve )
atom . packages . disablePackage ( packageName )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
expect ( atom . packages . getActivePackages ( ) ) . not . toContain ( pack )
expect ( atom . config . get ( 'core.disabledPackages' ) ) . toContain ( packageName )
2017-09-29 02:18:56 +03:00
} )
it ( 'returns null if the package cannot be loaded' , ( ) => {
spyOn ( console , 'warn' )
expect ( atom . packages . enablePackage ( 'this-doesnt-exist' ) ) . toBeNull ( )
expect ( console . warn . callCount ) . toBe ( 1 )
} )
it ( 'does not disable an already disabled package' , ( ) => {
const packageName = 'package-with-main'
atom . config . pushAtKeyPath ( 'core.disabledPackages' , packageName )
atom . packages . observeDisabledPackages ( )
expect ( atom . config . get ( 'core.disabledPackages' ) ) . toContain ( packageName )
atom . packages . disablePackage ( packageName )
2019-02-22 10:55:17 +03:00
const packagesDisabled = atom . config
. get ( 'core.disabledPackages' )
. filter ( pack => pack === packageName )
2017-09-29 02:18:56 +03:00
expect ( packagesDisabled . length ) . toEqual ( 1 )
} )
} )
describe ( 'with themes' , ( ) => {
2017-09-29 03:04:46 +03:00
beforeEach ( ( ) => atom . themes . activateThemes ( ) )
afterEach ( ( ) => atom . themes . deactivateThemes ( ) )
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
it ( 'enables and disables a theme' , async ( ) => {
2017-09-29 02:18:56 +03:00
const packageName = 'theme-with-package-file'
expect ( atom . config . get ( 'core.themes' ) ) . not . toContain ( packageName )
2019-02-22 10:55:17 +03:00
expect ( atom . config . get ( 'core.disabledPackages' ) ) . not . toContain (
packageName
)
2017-09-29 02:18:56 +03:00
// enabling of theme
2017-09-29 03:04:46 +03:00
const pack = atom . packages . enablePackage ( packageName )
2019-02-22 10:55:17 +03:00
await new Promise ( resolve =>
atom . packages . onDidActivatePackage ( resolve )
)
2017-09-29 03:04:46 +03:00
expect ( atom . packages . isPackageActive ( packageName ) ) . toBe ( true )
expect ( atom . config . get ( 'core.themes' ) ) . toContain ( packageName )
2019-02-22 10:55:17 +03:00
expect ( atom . config . get ( 'core.disabledPackages' ) ) . not . toContain (
packageName
)
2017-09-29 02:18:56 +03:00
2017-09-29 03:04:46 +03:00
await new Promise ( resolve => {
atom . themes . onDidChangeActiveThemes ( resolve )
atom . packages . disablePackage ( packageName )
2017-09-29 02:18:56 +03:00
} )
2017-09-29 03:04:46 +03:00
expect ( atom . packages . getActivePackages ( ) ) . not . toContain ( pack )
expect ( atom . config . get ( 'core.themes' ) ) . not . toContain ( packageName )
expect ( atom . config . get ( 'core.themes' ) ) . not . toContain ( packageName )
2019-02-22 10:55:17 +03:00
expect ( atom . config . get ( 'core.disabledPackages' ) ) . not . toContain (
packageName
)
2017-09-29 02:18:56 +03:00
} )
} )
} )
} )