2019-01-19 12:00:51 +00:00
import fs from 'fs'
import path from 'path'
import consola from 'consola'
import { chainFn } from '@nuxt/utils'
import ModuleContainer from '../src/module'
jest . mock ( 'fs' , ( ) => ( {
2019-03-03 08:12:46 +00:00
existsSync : Boolean ,
2019-06-29 04:49:55 +00:00
closeSync : Boolean ,
realpath : jest . fn ( )
2019-01-19 12:00:51 +00:00
} ) )
jest . mock ( 'hash-sum' , ( ) => src => ` hash( ${ src } ) ` )
jest . mock ( '@nuxt/utils' , ( ) => ( {
... jest . requireActual ( '@nuxt/utils' ) ,
chainFn : jest . fn ( ( ) => 'chainedFn' )
} ) )
2019-03-03 07:49:46 +00:00
const defaultOptions = {
modules : [ ] ,
2020-06-03 19:34:10 +00:00
buildModules : [ ] ,
_modules : [ ]
2019-03-03 07:49:46 +00:00
}
2019-01-19 12:00:51 +00:00
describe ( 'core: module' , ( ) => {
const requireModule = jest . fn ( src => options => Promise . resolve ( { src , options } ) )
beforeEach ( ( ) => {
consola . debug . mockClear ( )
consola . log . mockClear ( )
consola . warn . mockClear ( )
consola . error . mockClear ( )
consola . fatal . mockClear ( )
chainFn . mockClear ( )
requireModule . mockClear ( )
} )
test ( 'should construct module container' , ( ) => {
const nuxt = jest . fn ( )
nuxt . options = jest . fn ( )
const module = new ModuleContainer ( nuxt )
expect ( module . nuxt ) . toBe ( nuxt )
expect ( module . options ) . toBe ( nuxt . options )
expect ( module . requiredModules ) . toEqual ( { } )
} )
test ( 'should call hooks and addModule when ready' , async ( ) => {
const nuxt = {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
modules : [ jest . fn ( ) , jest . fn ( ) ]
} ,
callHook : jest . fn ( )
}
const module = new ModuleContainer ( nuxt )
module . addModule = jest . fn ( )
await module . ready ( )
expect ( nuxt . callHook ) . toBeCalledTimes ( 2 )
expect ( nuxt . callHook ) . nthCalledWith ( 1 , 'modules:before' , module , module . options . modules )
expect ( nuxt . callHook ) . nthCalledWith ( 2 , 'modules:done' , module )
expect ( module . addModule ) . toBeCalledTimes ( 2 )
expect ( module . addModule ) . nthCalledWith ( 1 , module . options . modules [ 0 ] )
expect ( module . addModule ) . nthCalledWith ( 2 , module . options . modules [ 1 ] )
} )
test ( 'should display deprecated message for addVendor' , ( ) => {
2019-03-03 07:49:46 +00:00
new ModuleContainer ( {
... defaultOptions
} ) . addVendor ( )
2019-01-19 12:00:51 +00:00
expect ( consola . warn ) . toBeCalledTimes ( 1 )
expect ( consola . warn ) . toBeCalledWith ( 'addVendor has been deprecated due to webpack4 optimization' )
} )
test ( 'should add string template' , ( ) => {
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
build : {
templates : [ ]
}
}
} )
const template = module . addTemplate ( '/var/nuxt/test' )
const expected = {
2019-11-26 22:42:39 +00:00
dst : 'nuxt.test.hash(/var/nuxt/test)' ,
options : undefined ,
src : '/var/nuxt/test'
2019-01-19 12:00:51 +00:00
}
expect ( template ) . toEqual ( expected )
expect ( module . options . build . templates ) . toEqual ( [ expected ] )
} )
test ( 'should add object template' , ( ) => {
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
build : {
templates : [ ]
}
}
} )
const template = module . addTemplate ( {
src : '/var/nuxt/test' ,
options : { test : true }
} )
const expected = {
2019-11-26 22:42:39 +00:00
dst : 'nuxt.test.hash(/var/nuxt/test)' ,
options : { test : true } ,
src : '/var/nuxt/test'
2019-01-19 12:00:51 +00:00
}
expect ( template ) . toEqual ( expected )
expect ( module . options . build . templates ) . toEqual ( [ expected ] )
} )
test ( 'should use filename in preference to calculation' , ( ) => {
const module = new ModuleContainer ( {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
options : {
build : {
templates : [ ]
}
}
} )
const template = module . addTemplate ( {
src : '/var/nuxt/test' ,
fileName : '/var/nuxt/dist/test'
} )
const expected = {
2019-11-26 22:42:39 +00:00
dst : '/var/nuxt/dist/test' ,
options : undefined ,
src : '/var/nuxt/test'
2019-01-19 12:00:51 +00:00
}
expect ( template ) . toEqual ( expected )
expect ( module . options . build . templates ) . toEqual ( [ expected ] )
} )
test ( 'should throw error when template invalid' , ( ) => {
2019-03-03 07:49:46 +00:00
const module = new ModuleContainer ( {
options : {
... defaultOptions
}
} )
2019-01-19 12:00:51 +00:00
expect ( ( ) => module . addTemplate ( ) ) . toThrow ( 'Invalid template: undefined' )
} )
test ( 'should throw error when template not found' , ( ) => {
2019-03-03 07:49:46 +00:00
const module = new ModuleContainer ( {
options : {
... defaultOptions
}
} )
2019-01-19 12:00:51 +00:00
fs . existsSync = jest . fn ( ( ) => false )
expect ( ( ) => module . addTemplate ( '/var/nuxt/test' ) ) . toThrow ( 'Template src not found: /var/nuxt/test' )
fs . existsSync = jest . fn ( Boolean )
} )
test ( 'should add plugin into module' , ( ) => {
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
buildDir : '/var/nuxt/build' ,
plugins : [ ]
}
} )
module . addTemplate = jest . fn ( ( ) => ( { dst : 'nuxt.test.template' } ) )
module . addPlugin ( { ssr : false , mode : 'client' } )
expect ( module . options . plugins ) . toEqual ( [ {
src : path . join ( '/var/nuxt/build' , 'nuxt.test.template' ) ,
ssr : false ,
mode : 'client'
} ] )
} )
test ( 'should add layout into module' , ( ) => {
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
layouts : { }
}
} )
module . addTemplate = jest . fn ( ( ) => ( {
dst : 'nuxt.test.template' ,
src : '/var/nuxt/src'
} ) )
module . addLayout ( { } , 'test-layout' )
expect ( module . options . layouts ) . toEqual ( { 'test-layout' : './nuxt.test.template' } )
} )
test ( 'should display deprecated message when registration is duplicate' , ( ) => {
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
layouts : {
'test-layout' : 'test.template'
}
}
} )
module . addTemplate = jest . fn ( ( ) => ( {
dst : 'nuxt.test.template' ,
src : '/var/nuxt/src'
} ) )
module . addLayout ( { } , 'test-layout' )
expect ( consola . warn ) . toBeCalledTimes ( 1 )
expect ( consola . warn ) . toBeCalledWith ( 'Duplicate layout registration, "test-layout" has been registered as "test.template"' )
} )
test ( 'should register error layout at same time' , ( ) => {
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
layouts : { }
}
} )
module . addErrorLayout = jest . fn ( )
module . addTemplate = jest . fn ( ( ) => ( {
dst : 'nuxt.test.template' ,
src : '/var/nuxt/src'
} ) )
module . addLayout ( { } , 'error' )
2019-11-26 22:42:39 +00:00
expect ( module . options . layouts ) . toEqual ( { error : './nuxt.test.template' } )
2019-01-19 12:00:51 +00:00
expect ( module . addErrorLayout ) . toBeCalledTimes ( 1 )
expect ( module . addErrorLayout ) . toBeCalledWith ( 'nuxt.test.template' )
} )
test ( 'should add error layout' , ( ) => {
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
rootDir : '/var/nuxt' ,
buildDir : '/var/nuxt/build' ,
layouts : { }
}
} )
module . addErrorLayout ( 'error.template' )
expect ( module . options . ErrorPage ) . toEqual ( '~/build/error.template' )
} )
test ( 'should add server middleware' , ( ) => {
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
serverMiddleware : [ ]
}
} )
module . addServerMiddleware ( ( ) => { } )
module . addServerMiddleware ( ( ) => { } )
expect ( module . options . serverMiddleware ) . toHaveLength ( 2 )
expect ( module . options . serverMiddleware ) . toEqual ( [ expect . any ( Function ) , expect . any ( Function ) ] )
} )
test ( 'should chain build.extend' , ( ) => {
const extend = ( ) => { }
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
build : { extend }
}
} )
const newExtend = ( ) => { }
module . extendBuild ( newExtend )
expect ( chainFn ) . toBeCalledTimes ( 1 )
expect ( chainFn ) . toBeCalledWith ( extend , newExtend )
expect ( module . options . build . extend ) . toEqual ( 'chainedFn' )
} )
test ( 'should chain router.extendRoutes' , ( ) => {
const extendRoutes = ( ) => { }
const module = new ModuleContainer ( {
options : {
2019-03-03 07:49:46 +00:00
... defaultOptions ,
2019-01-19 12:00:51 +00:00
router : { extendRoutes }
}
} )
const newExtendRoutes = ( ) => { }
module . extendRoutes ( newExtendRoutes )
expect ( chainFn ) . toBeCalledTimes ( 1 )
expect ( chainFn ) . toBeCalledWith ( extendRoutes , newExtendRoutes )
expect ( module . options . router . extendRoutes ) . toEqual ( 'chainedFn' )
} )
test ( 'should call addModule when require module' , ( ) => {
const module = new ModuleContainer ( {
2019-03-03 07:49:46 +00:00
options : {
... defaultOptions
}
2019-01-19 12:00:51 +00:00
} )
module . addModule = jest . fn ( )
const moduleOpts = { }
module . requireModule ( moduleOpts )
expect ( module . addModule ) . toBeCalledTimes ( 1 )
2020-05-18 11:58:48 +00:00
expect ( module . addModule ) . toBeCalledWith ( moduleOpts )
2019-01-19 12:00:51 +00:00
} )
test ( 'should add string module' , async ( ) => {
const module = new ModuleContainer ( {
resolver : { requireModule } ,
2019-03-03 07:49:46 +00:00
options : {
... defaultOptions
}
2019-01-19 12:00:51 +00:00
} )
const result = await module . addModule ( 'moduleTest' )
expect ( requireModule ) . toBeCalledTimes ( 1 )
2019-03-13 10:24:39 +00:00
expect ( requireModule ) . toBeCalledWith ( 'moduleTest' , { useESM : true } )
2019-01-19 12:00:51 +00:00
expect ( module . requiredModules ) . toEqual ( {
moduleTest : {
handler : expect . any ( Function ) ,
options : undefined ,
src : 'moduleTest'
}
} )
expect ( result ) . toEqual ( { src : 'moduleTest' , options : { } } )
} )
2019-02-05 11:35:42 +00:00
test ( 'should add function module' , async ( ) => {
const module = new ModuleContainer ( {
resolver : { requireModule } ,
2019-03-03 07:49:46 +00:00
options : {
... defaultOptions
}
2019-02-05 11:35:42 +00:00
} )
const functionModule = function ( options ) {
return Promise . resolve ( options )
}
functionModule . meta = { name : 'moduleTest' }
const result = await module . addModule ( functionModule )
expect ( requireModule ) . not . toBeCalled ( )
expect ( module . requiredModules ) . toEqual ( {
moduleTest : {
handler : expect . any ( Function ) ,
options : undefined ,
src : functionModule
}
} )
expect ( result ) . toEqual ( { } )
} )
2019-01-19 12:00:51 +00:00
test ( 'should add array module' , async ( ) => {
const module = new ModuleContainer ( {
resolver : { requireModule } ,
2019-03-03 07:49:46 +00:00
options : {
... defaultOptions
}
2019-01-19 12:00:51 +00:00
} )
const result = await module . addModule ( [ 'moduleTest' , { test : true } ] )
expect ( requireModule ) . toBeCalledTimes ( 1 )
2019-03-13 10:24:39 +00:00
expect ( requireModule ) . toBeCalledWith ( 'moduleTest' , { useESM : true } )
2019-01-19 12:00:51 +00:00
expect ( module . requiredModules ) . toEqual ( {
moduleTest : {
handler : expect . any ( Function ) ,
options : {
test : true
} ,
src : 'moduleTest'
}
} )
expect ( result ) . toEqual ( { src : 'moduleTest' , options : { test : true } } )
} )
test ( 'should add object module' , async ( ) => {
const module = new ModuleContainer ( {
resolver : { requireModule } ,
2019-03-03 07:49:46 +00:00
options : {
... defaultOptions
}
2019-01-19 12:00:51 +00:00
} )
const result = await module . addModule ( {
2020-05-18 11:58:48 +00:00
src : 'pathToModule' ,
2019-01-19 12:00:51 +00:00
options : { test : true } ,
2020-05-18 11:58:48 +00:00
handler : opts => opts
2019-01-19 12:00:51 +00:00
} )
expect ( requireModule ) . not . toBeCalled ( )
expect ( module . requiredModules ) . toEqual ( {
2020-05-18 11:58:48 +00:00
pathToModule : {
src : 'pathToModule' ,
options : { test : true } ,
handler : expect . any ( Function )
2019-01-19 12:00:51 +00:00
}
} )
expect ( result ) . toEqual ( { test : true } )
} )
2019-02-04 11:31:24 +00:00
test ( 'should throw error when handler is not function' , async ( ) => {
2019-01-19 12:00:51 +00:00
const module = new ModuleContainer ( {
resolver : { requireModule : ( ) => false } ,
2019-03-03 07:49:46 +00:00
options : {
... defaultOptions
}
2019-01-19 12:00:51 +00:00
} )
2019-02-04 11:31:24 +00:00
await expect ( module . addModule ( 'moduleTest' ) ) . rejects . toThrow ( 'Module should export a function: moduleTest' )
2019-01-19 12:00:51 +00:00
} )
test ( 'should prevent multiple adding when requireOnce is enabled' , async ( ) => {
const module = new ModuleContainer ( {
resolver : { requireModule } ,
2019-03-03 07:49:46 +00:00
options : {
... defaultOptions
}
2019-01-19 12:00:51 +00:00
} )
const handler = jest . fn ( ( ) => true )
handler . meta = {
name : 'moduleTest'
}
const first = await module . addModule ( { handler } , true )
const second = await module . addModule ( { handler } , true )
expect ( first ) . toEqual ( true )
expect ( second ) . toBeUndefined ( )
expect ( handler ) . toBeCalledTimes ( 1 )
expect ( module . requiredModules . moduleTest ) . toBeDefined ( )
} )
2020-03-13 20:25:53 +00:00
test ( 'should prevent adding not installed buildModules' , async ( ) => {
const module = new ModuleContainer ( {
resolver : { requireModule } ,
options : {
... defaultOptions ,
buildModules : [ 'test-build-module' ]
}
} )
requireModule . mockImplementationOnce ( ( ) => {
const moduleNotFound = new Error ( )
moduleNotFound . code = 'MODULE_NOT_FOUND'
throw moduleNotFound
} )
const result = await module . addModule ( 'test-build-module' , true )
expect ( result ) . toBeUndefined ( )
2020-04-14 09:26:40 +00:00
expect ( consola . warn ) . toBeCalledWith ( 'Module `test-build-module` not found. Please ensure `test-build-module` is in `devDependencies` and installed. HINT: During build step, for npm/yarn, `NODE_ENV=production` or `--production` should NOT be used. Silently ignoring module as programmatic usage detected.' )
2020-03-13 20:25:53 +00:00
} )
2019-01-19 12:00:51 +00:00
} )