import os from 'os' ; import { TempDir } from './util' ; import { cosmiconfig as cosmiconfigModule , cosmiconfigSync as cosmiconfigSyncModule , defaultLoaders , LoaderSync , } from '../src' ; import { Loaders } from '../src/types' ; const temp = new TempDir ( ) ; function getLoaderFunctionsByName ( loaders ) { const loaderFunctionsByName = Object . entries ( loaders ) . reduce ( ( acc , [ extension , loader ] ) => { return { ... acc , [ extension ] : loader . name , } ; } , { } ) ; return loaderFunctionsByName ; } let cosmiconfig ; let cosmiconfigSync ; let createExplorerMock ; let createExplorerSyncMock ; describe ( 'cosmiconfig' , ( ) => { const moduleName = 'foo' ; beforeEach ( ( ) => { temp . clean ( ) ; createExplorerMock = jest . fn ( ) ; jest . doMock ( '../src/Explorer' , ( ) => { return { Explorer : class FakeExplorer { constructor ( options ) { createExplorerMock ( options ) ; const { Explorer } = jest . requireActual ( '../src/Explorer' ) ; return new Explorer ( options ) ; } } , } ; } ) ; createExplorerSyncMock = jest . fn ( ) ; jest . doMock ( '../src/ExplorerSync' , ( ) => { return { ExplorerSync : class FakeExplorerSync { constructor ( options ) { createExplorerSyncMock ( options ) ; const { ExplorerSync } = jest . requireActual ( '../src/ExplorerSync' ) ; return new ExplorerSync ( options ) ; } } , } ; } ) ; const index = require ( '../src/index' ) ; cosmiconfig = index . cosmiconfig ; cosmiconfigSync = index . cosmiconfigSync ; } ) ; afterAll ( ( ) => { temp . deleteTempDir ( ) ; } ) ; describe ( 'creates explorer with default options if not specified' , ( ) => { const checkResult = ( mock ) => { expect ( mock . mock . calls . length ) . toEqual ( 1 ) ; expect ( mock . mock . calls [ 0 ] . length ) . toEqual ( 1 ) ; const { transform , loaders , ... explorerOptions } = mock . mock . calls [ 0 ] [ 0 ] ; expect ( transform . name ) . toBe ( 'identity' ) ; const loaderFunctionsByName = getLoaderFunctionsByName ( loaders ) ; expect ( loaderFunctionsByName ) . toEqual ( { '.cjs' : 'loadJs' , '.js' : 'loadJs' , '.json' : 'loadJson' , '.yaml' : 'loadYaml' , '.yml' : 'loadYaml' , noExt : 'loadYaml' , } ) ; expect ( explorerOptions ) . toEqual ( { packageProp : moduleName , searchPlaces : [ 'package.json' , `.${ moduleName }rc` , `.${ moduleName }rc.json` , `.${ moduleName }rc.yaml` , `.${ moduleName }rc.yml` , `.${ moduleName }rc.js` , `.${ moduleName }rc.cjs` , `${ moduleName }.config.js` , `${ moduleName }.config.cjs` , ] , ignoreEmptySearchPlaces : true , stopDir : os . homedir ( ) , cache : true , } ) ; } ; test ( 'async' , ( ) => { cosmiconfig ( moduleName ) ; checkResult ( createExplorerMock ) ; } ) ; test ( 'sync' , ( ) => { cosmiconfigSync ( moduleName ) ; checkResult ( createExplorerSyncMock ) ; } ) ; } ) ; describe ( 'defaults transform to sync identity function' , ( ) => { const checkResult = ( mock ) => { const explorerOptions = mock . mock . calls [ 0 ] [ 0 ] ; const x = { } ; expect ( explorerOptions . transform ( x ) ) . toBe ( x ) ; } ; test ( 'async' , ( ) => { cosmiconfig ( moduleName ) ; checkResult ( createExplorerMock ) ; } ) ; test ( 'sync' , ( ) => { cosmiconfigSync ( moduleName ) ; checkResult ( createExplorerSyncMock ) ; } ) ; } ) ; describe ( 'creates explorer with preference for given options over defaults' , ( ) => { beforeEach ( ( ) => { temp . createFile ( 'foo.json' , '{ "foo": true }' ) ; } ) ; const noExtLoader = ( ) => { } ; const jsLoader = ( ) => { } ; const jsonLoader = ( ) => { } ; const yamlLoader = ( ) => { } ; const options = { stopDir : __dirname , cache : false , searchPlaces : [ '.foorc.json' , 'wildandfree.js' ] , packageProp : 'wildandfree' , ignoreEmptySearchPlaces : false , loaders : { noExt : noExtLoader , '.cjs' : jsLoader , '.js' : jsLoader , '.json' : jsonLoader , '.yaml' : yamlLoader , } , } ; const checkResult = ( mock ) => { expect ( mock . mock . calls . length ) . toEqual ( 1 ) ; expect ( mock . mock . calls [ 0 ] . length ) . toEqual ( 1 ) ; const { transform , loaders , ... explorerOptions } = mock . mock . calls [ 0 ] [ 0 ] ; expect ( transform . name ) . toBe ( 'identity' ) ; const loaderFunctionsByName = getLoaderFunctionsByName ( loaders ) ; expect ( loaderFunctionsByName ) . toEqual ( { '.cjs' : 'jsLoader' , '.js' : 'jsLoader' , '.json' : 'jsonLoader' , '.yaml' : 'yamlLoader' , '.yml' : 'loadYaml' , noExt : 'noExtLoader' , } ) ; expect ( explorerOptions ) . toEqual ( { packageProp : 'wildandfree' , searchPlaces : [ '.foorc.json' , 'wildandfree.js' ] , ignoreEmptySearchPlaces : false , stopDir : __dirname , cache : false , } ) ; } ; test ( 'async' , ( ) => { cosmiconfig ( moduleName , options ) ; checkResult ( createExplorerMock ) ; } ) ; test ( 'sync' , ( ) => { cosmiconfigSync ( moduleName , options ) ; checkResult ( createExplorerSyncMock ) ; } ) ; } ) ; describe ( 'errors if loader is not passed a function' , ( ) => { beforeEach ( ( ) => { temp . createFile ( 'a/b/c/d/e/f/.foorc.things' , 'one\ntwo\nthree\t\t\n  four\n' ) ; } ) ; const explorerOptions = { stopDir : temp . absolutePath ( '.' ) , searchPlaces : [ '.foorc.things' ] , loaders : { '.things' : 1 , } , } ; const expectedError = 'loader for extension ".things" is not a function (type provided: "number"), so searchPlaces item ".foorc.things" is invalid' ; test ( 'async' , ( ) => { expect ( ( ) => cosmiconfig ( 'foo' , explorerOptions ) ) . toThrow ( expectedError ) ; } ) ; test ( 'sync' , ( ) => { expect ( ( ) => cosmiconfigSync ( 'foo' , explorerOptions ) ) . toThrow ( expectedError ) ; } ) ; } ) ; test ( 'cannot mutate default loaders' , ( ) => { const expectedError = "Cannot delete property '.js' of #<Object>" ; expect ( ( ) => delete defaultLoaders [ '.js' ] ) . toThrow ( expectedError ) ; } ) ; } ) ;