2020-10-30 16:40:57 +03:00
const path = require ( 'path' ) ;
const Package = require ( '../src/package' ) ;
const ThemePackage = require ( '../src/theme-package' ) ;
const { mockLocalStorage } = require ( './spec-helper' ) ;
describe ( 'Package' , function ( ) {
const build = ( constructor , packagePath ) =>
new constructor ( {
path : packagePath ,
packageManager : atom . packages ,
config : atom . config ,
styleManager : atom . styles ,
notificationManager : atom . notifications ,
keymapManager : atom . keymaps ,
commandRegistry : atom . command ,
grammarRegistry : atom . grammars ,
themeManager : atom . themes ,
menuManager : atom . menu ,
contextMenuManager : atom . contextMenu ,
deserializerManager : atom . deserializers ,
viewRegistry : atom . views
} ) ;
const buildPackage = packagePath => build ( Package , packagePath ) ;
const buildThemePackage = themePath => build ( ThemePackage , themePath ) ;
describe ( 'when the package contains incompatible native modules' , function ( ) {
beforeEach ( function ( ) {
atom . packages . devMode = false ;
mockLocalStorage ( ) ;
} ) ;
afterEach ( ( ) => ( atom . packages . devMode = true ) ) ;
it ( 'does not activate it' , function ( ) {
const packagePath = atom . project
. getDirectories ( ) [ 0 ]
. resolve ( 'packages/package-with-incompatible-native-module' ) ;
const pack = buildPackage ( packagePath ) ;
expect ( pack . isCompatible ( ) ) . toBe ( false ) ;
2021-03-07 05:00:57 +03:00
expect ( pack . incompatibleModules [ 0 ] . name ) . toBe ( 'native-module' ) ;
expect ( pack . incompatibleModules [ 0 ] . path ) . toBe (
path . join ( packagePath , 'node_modules' , 'native-module' )
) ;
} ) ;
it ( 'detects the package as incompatible even if .node file is loaded conditionally' , function ( ) {
const packagePath = atom . project
. getDirectories ( ) [ 0 ]
. resolve (
'packages/package-with-incompatible-native-module-loaded-conditionally'
) ;
const pack = buildPackage ( packagePath ) ;
expect ( pack . isCompatible ( ) ) . toBe ( false ) ;
2020-10-30 16:40:57 +03:00
expect ( pack . incompatibleModules [ 0 ] . name ) . toBe ( 'native-module' ) ;
expect ( pack . incompatibleModules [ 0 ] . path ) . toBe (
path . join ( packagePath , 'node_modules' , 'native-module' )
) ;
} ) ;
it ( "utilizes _atomModuleCache if present to determine the package's native dependencies" , function ( ) {
let packagePath = atom . project
. getDirectories ( ) [ 0 ]
. resolve ( 'packages/package-with-ignored-incompatible-native-module' ) ;
let pack = buildPackage ( packagePath ) ;
expect ( pack . getNativeModuleDependencyPaths ( ) . length ) . toBe ( 1 ) ; // doesn't see the incompatible module
expect ( pack . isCompatible ( ) ) . toBe ( true ) ;
packagePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/package-with-cached-incompatible-native-module' )
) ;
pack = buildPackage ( packagePath ) ;
expect ( pack . isCompatible ( ) ) . toBe ( false ) ;
} ) ;
it ( 'caches the incompatible native modules in local storage' , function ( ) {
const packagePath = atom . project
. getDirectories ( ) [ 0 ]
. resolve ( 'packages/package-with-incompatible-native-module' ) ;
expect ( buildPackage ( packagePath ) . isCompatible ( ) ) . toBe ( false ) ;
expect ( global . localStorage . getItem . callCount ) . toBe ( 1 ) ;
expect ( global . localStorage . setItem . callCount ) . toBe ( 1 ) ;
expect ( buildPackage ( packagePath ) . isCompatible ( ) ) . toBe ( false ) ;
expect ( global . localStorage . getItem . callCount ) . toBe ( 2 ) ;
expect ( global . localStorage . setItem . callCount ) . toBe ( 1 ) ;
} ) ;
it ( 'logs an error to the console describing the problem' , function ( ) {
const packagePath = atom . project
. getDirectories ( ) [ 0 ]
. resolve ( 'packages/package-with-incompatible-native-module' ) ;
spyOn ( console , 'warn' ) ;
spyOn ( atom . notifications , 'addFatalError' ) ;
buildPackage ( packagePath ) . activateNow ( ) ;
expect ( atom . notifications . addFatalError ) . not . toHaveBeenCalled ( ) ;
expect ( console . warn . callCount ) . toBe ( 1 ) ;
expect ( console . warn . mostRecentCall . args [ 0 ] ) . toContain (
'it requires one or more incompatible native modules (native-module)'
) ;
} ) ;
} ) ;
describe ( '::rebuild()' , function ( ) {
beforeEach ( function ( ) {
atom . packages . devMode = false ;
mockLocalStorage ( ) ;
} ) ;
afterEach ( ( ) => ( atom . packages . devMode = true ) ) ;
it ( 'returns a promise resolving to the results of `apm rebuild`' , function ( ) {
const packagePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/package-with-index' )
) ;
const pack = buildPackage ( packagePath ) ;
const rebuildCallbacks = [ ] ;
spyOn ( pack , 'runRebuildProcess' ) . andCallFake ( callback =>
rebuildCallbacks . push ( callback )
) ;
const promise = pack . rebuild ( ) ;
rebuildCallbacks [ 0 ] ( {
code : 0 ,
stdout : 'stdout output' ,
stderr : 'stderr output'
} ) ;
waitsFor ( done =>
promise . then ( function ( result ) {
expect ( result ) . toEqual ( {
code : 0 ,
stdout : 'stdout output' ,
stderr : 'stderr output'
} ) ;
done ( ) ;
} )
) ;
} ) ;
it ( 'persists build failures in local storage' , function ( ) {
const packagePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/package-with-index' )
) ;
const pack = buildPackage ( packagePath ) ;
expect ( pack . isCompatible ( ) ) . toBe ( true ) ;
expect ( pack . getBuildFailureOutput ( ) ) . toBeNull ( ) ;
const rebuildCallbacks = [ ] ;
spyOn ( pack , 'runRebuildProcess' ) . andCallFake ( callback =>
rebuildCallbacks . push ( callback )
) ;
pack . rebuild ( ) ;
rebuildCallbacks [ 0 ] ( { code : 13 , stderr : 'It is broken' } ) ;
expect ( pack . getBuildFailureOutput ( ) ) . toBe ( 'It is broken' ) ;
expect ( pack . getIncompatibleNativeModules ( ) ) . toEqual ( [ ] ) ;
expect ( pack . isCompatible ( ) ) . toBe ( false ) ;
// A different package instance has the same failure output (simulates reload)
const pack2 = buildPackage ( packagePath ) ;
expect ( pack2 . getBuildFailureOutput ( ) ) . toBe ( 'It is broken' ) ;
expect ( pack2 . isCompatible ( ) ) . toBe ( false ) ;
// Clears the build failure after a successful build
pack . rebuild ( ) ;
rebuildCallbacks [ 1 ] ( { code : 0 , stdout : 'It worked' } ) ;
expect ( pack . getBuildFailureOutput ( ) ) . toBeNull ( ) ;
expect ( pack2 . getBuildFailureOutput ( ) ) . toBeNull ( ) ;
} ) ;
it ( 'sets cached incompatible modules to an empty array when the rebuild completes (there may be a build error, but rebuilding *deletes* native modules)' , function ( ) {
const packagePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/package-with-incompatible-native-module' )
) ;
const pack = buildPackage ( packagePath ) ;
expect ( pack . getIncompatibleNativeModules ( ) . length ) . toBeGreaterThan ( 0 ) ;
const rebuildCallbacks = [ ] ;
spyOn ( pack , 'runRebuildProcess' ) . andCallFake ( callback =>
rebuildCallbacks . push ( callback )
) ;
pack . rebuild ( ) ;
expect ( pack . getIncompatibleNativeModules ( ) . length ) . toBeGreaterThan ( 0 ) ;
rebuildCallbacks [ 0 ] ( { code : 0 , stdout : 'It worked' } ) ;
expect ( pack . getIncompatibleNativeModules ( ) . length ) . toBe ( 0 ) ;
} ) ;
} ) ;
describe ( 'theme' , function ( ) {
let [ editorElement , theme ] = [ ] ;
beforeEach ( function ( ) {
editorElement = document . createElement ( 'atom-text-editor' ) ;
jasmine . attachToDOM ( editorElement ) ;
} ) ;
afterEach ( ( ) =>
waitsForPromise ( function ( ) {
if ( theme != null ) {
return Promise . resolve ( theme . deactivate ( ) ) ;
}
} )
) ;
describe ( 'when the theme contains a single style file' , function ( ) {
it ( 'loads and applies css' , function ( ) {
expect ( getComputedStyle ( editorElement ) . paddingBottom ) . not . toBe (
'1234px'
) ;
const themePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/theme-with-index-css' )
) ;
theme = buildThemePackage ( themePath ) ;
theme . activate ( ) ;
expect ( getComputedStyle ( editorElement ) . paddingTop ) . toBe ( '1234px' ) ;
} ) ;
it ( 'parses, loads and applies less' , function ( ) {
expect ( getComputedStyle ( editorElement ) . paddingBottom ) . not . toBe (
'1234px'
) ;
const themePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/theme-with-index-less' )
) ;
theme = buildThemePackage ( themePath ) ;
theme . activate ( ) ;
expect ( getComputedStyle ( editorElement ) . paddingTop ) . toBe ( '4321px' ) ;
} ) ;
} ) ;
describe ( 'when the theme contains a package.json file' , ( ) =>
it ( 'loads and applies stylesheets from package.json in the correct order' , function ( ) {
expect ( getComputedStyle ( editorElement ) . paddingTop ) . not . toBe ( '101px' ) ;
expect ( getComputedStyle ( editorElement ) . paddingRight ) . not . toBe ( '102px' ) ;
expect ( getComputedStyle ( editorElement ) . paddingBottom ) . not . toBe ( '103px' ) ;
const themePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/theme-with-package-file' )
) ;
theme = buildThemePackage ( themePath ) ;
theme . activate ( ) ;
expect ( getComputedStyle ( editorElement ) . paddingTop ) . toBe ( '101px' ) ;
expect ( getComputedStyle ( editorElement ) . paddingRight ) . toBe ( '102px' ) ;
expect ( getComputedStyle ( editorElement ) . paddingBottom ) . toBe ( '103px' ) ;
} ) ) ;
describe ( 'when the theme does not contain a package.json file and is a directory' , ( ) =>
it ( 'loads all stylesheet files in the directory' , function ( ) {
expect ( getComputedStyle ( editorElement ) . paddingTop ) . not . toBe ( '10px' ) ;
expect ( getComputedStyle ( editorElement ) . paddingRight ) . not . toBe ( '20px' ) ;
expect ( getComputedStyle ( editorElement ) . paddingBottom ) . not . toBe ( '30px' ) ;
const themePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/theme-without-package-file' )
) ;
theme = buildThemePackage ( themePath ) ;
theme . activate ( ) ;
expect ( getComputedStyle ( editorElement ) . paddingTop ) . toBe ( '10px' ) ;
expect ( getComputedStyle ( editorElement ) . paddingRight ) . toBe ( '20px' ) ;
expect ( getComputedStyle ( editorElement ) . paddingBottom ) . toBe ( '30px' ) ;
} ) ) ;
describe ( 'reloading a theme' , function ( ) {
beforeEach ( function ( ) {
const themePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/theme-with-package-file' )
) ;
theme = buildThemePackage ( themePath ) ;
theme . activate ( ) ;
} ) ;
it ( 'reloads without readding to the stylesheets list' , function ( ) {
expect ( theme . getStylesheetPaths ( ) . length ) . toBe ( 3 ) ;
theme . reloadStylesheets ( ) ;
expect ( theme . getStylesheetPaths ( ) . length ) . toBe ( 3 ) ;
} ) ;
} ) ;
describe ( 'events' , function ( ) {
beforeEach ( function ( ) {
const themePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/theme-with-package-file' )
) ;
theme = buildThemePackage ( themePath ) ;
theme . activate ( ) ;
} ) ;
it ( 'deactivated event fires on .deactivate()' , function ( ) {
let spy ;
theme . onDidDeactivate ( ( spy = jasmine . createSpy ( ) ) ) ;
waitsForPromise ( ( ) => Promise . resolve ( theme . deactivate ( ) ) ) ;
runs ( ( ) => expect ( spy ) . toHaveBeenCalled ( ) ) ;
} ) ;
} ) ;
} ) ;
describe ( '.loadMetadata()' , function ( ) {
let [ packagePath , metadata ] = [ ] ;
beforeEach ( function ( ) {
packagePath = _ _guard _ _ ( atom . project . getDirectories ( ) [ 0 ] , x =>
x . resolve ( 'packages/package-with-different-directory-name' )
) ;
metadata = atom . packages . loadPackageMetadata ( packagePath , true ) ;
} ) ;
it ( 'uses the package name defined in package.json' , ( ) =>
expect ( metadata . name ) . toBe ( 'package-with-a-totally-different-name' ) ) ;
} ) ;
describe ( 'the initialize() hook' , function ( ) {
it ( 'gets called when the package is activated' , function ( ) {
const packagePath = atom . project
. getDirectories ( ) [ 0 ]
. resolve ( 'packages/package-with-deserializers' ) ;
const pack = buildPackage ( packagePath ) ;
pack . requireMainModule ( ) ;
const { mainModule } = pack ;
spyOn ( mainModule , 'initialize' ) ;
expect ( mainModule . initialize ) . not . toHaveBeenCalled ( ) ;
pack . activate ( ) ;
expect ( mainModule . initialize ) . toHaveBeenCalled ( ) ;
expect ( mainModule . initialize . callCount ) . toBe ( 1 ) ;
} ) ;
it ( 'gets called when a deserializer is used' , function ( ) {
const packagePath = atom . project
. getDirectories ( ) [ 0 ]
. resolve ( 'packages/package-with-deserializers' ) ;
const pack = buildPackage ( packagePath ) ;
pack . requireMainModule ( ) ;
const { mainModule } = pack ;
spyOn ( mainModule , 'initialize' ) ;
pack . load ( ) ;
expect ( mainModule . initialize ) . not . toHaveBeenCalled ( ) ;
atom . deserializers . deserialize ( { deserializer : 'Deserializer1' , a : 'b' } ) ;
expect ( mainModule . initialize ) . toHaveBeenCalled ( ) ;
} ) ;
} ) ;
} ) ;
function _ _guard _ _ ( value , transform ) {
return typeof value !== 'undefined' && value !== null
? transform ( value )
: undefined ;
}