11'use strict' ;
22const {
3+ ArrayPrototypeFilter,
34 ArrayPrototypePush,
45 ArrayPrototypeSlice,
56 Error,
67 FunctionPrototypeBind,
78 FunctionPrototypeCall,
9+ ObjectAssign,
810 ObjectDefineProperty,
911 ObjectGetOwnPropertyDescriptor,
1012 ObjectGetPrototypeOf,
@@ -33,6 +35,7 @@ const {
3335 URLParse,
3436} = require ( 'internal/url' ) ;
3537const {
38+ deprecateProperty,
3639 emitExperimentalWarning,
3740 getStructuredStack,
3841 kEmptyObject,
@@ -61,6 +64,14 @@ const kSupportedFormats = [
6164 'module' ,
6265] ;
6366let sharedModuleState ;
67+ const deprecateNamedExports = deprecateProperty (
68+ 'namedExports' ,
69+ 'mock.module(): options.namedExports is deprecated. Use options.exports instead.' ,
70+ ) ;
71+ const deprecateDefaultExport = deprecateProperty (
72+ 'defaultExport' ,
73+ 'mock.module(): options.defaultExport is deprecated. Use options.exports.default instead.' ,
74+ ) ;
6475const {
6576 hooks : mockHooks ,
6677 mocks,
@@ -185,20 +196,16 @@ class MockModuleContext {
185196 baseURL,
186197 cache,
187198 caller,
188- defaultExport,
189199 format,
190200 fullPath,
191- hasDefaultExport,
192- namedExports,
201+ moduleExports,
193202 sharedState,
194203 specifier,
195204 } ) {
196205 const config = {
197206 __proto__ : null ,
198207 cache,
199- defaultExport,
200- hasDefaultExport,
201- namedExports,
208+ moduleExports,
202209 caller,
203210 } ;
204211
@@ -230,8 +237,8 @@ class MockModuleContext {
230237 __proto__ : null ,
231238 url : baseURL ,
232239 cache,
233- exportNames : ObjectKeys ( namedExports ) ,
234- hasDefaultExport,
240+ exportNames : ArrayPrototypeFilter ( ObjectKeys ( moduleExports ) , ( k ) => k !== 'default' ) ,
241+ hasDefaultExport : 'default' in moduleExports ,
235242 format,
236243 localVersion,
237244 active : true ,
@@ -241,8 +248,7 @@ class MockModuleContext {
241248 delete Module . _cache [ fullPath ] ;
242249 sharedState . mockExports . set ( baseURL , {
243250 __proto__ : null ,
244- defaultExport,
245- namedExports,
251+ moduleExports,
246252 } ) ;
247253 }
248254
@@ -627,14 +633,9 @@ class MockTracker {
627633 debug ( 'module mock entry, specifier = "%s", options = %o' , specifier , options ) ;
628634
629635 const {
630- cache = false ,
631- namedExports = kEmptyObject ,
632- defaultExport,
633- } = options ;
634- const hasDefaultExport = 'defaultExport' in options ;
635-
636- validateBoolean ( cache , 'options.cache' ) ;
637- validateObject ( namedExports , 'options.namedExports' ) ;
636+ cache,
637+ moduleExports,
638+ } = normalizeModuleMockOptions ( options ) ;
638639
639640 const sharedState = setupSharedModuleState ( ) ;
640641 const mockSpecifier = StringPrototypeStartsWith ( specifier , 'node:' ) ?
@@ -673,11 +674,9 @@ class MockTracker {
673674 baseURL : baseURL . href ,
674675 cache,
675676 caller,
676- defaultExport,
677677 format,
678678 fullPath,
679- hasDefaultExport,
680- namedExports,
679+ moduleExports,
681680 sharedState,
682681 specifier : mockSpecifier ,
683682 } ) ;
@@ -816,6 +815,73 @@ class MockTracker {
816815 }
817816}
818817
818+ function normalizeModuleMockOptions ( options ) {
819+ const { cache = false } = options ;
820+ validateBoolean ( cache , 'options.cache' ) ;
821+
822+ const hasExports = 'exports' in options ;
823+ const hasNamedExports = 'namedExports' in options ;
824+ const hasDefaultExport = 'defaultExport' in options ;
825+
826+ deprecateNamedExports ( options ) ;
827+ deprecateDefaultExport ( options ) ;
828+
829+ const moduleExports = { __proto__ : null } ;
830+
831+ if ( hasExports ) {
832+ validateObject ( options . exports , 'options.exports' ) ;
833+ }
834+
835+ if ( hasNamedExports ) {
836+ validateObject ( options . namedExports , 'options.namedExports' ) ;
837+ }
838+
839+ if ( hasExports && ( hasNamedExports || hasDefaultExport ) ) {
840+ let reason = "cannot be used with 'options.namedExports'" ;
841+
842+ if ( hasDefaultExport ) {
843+ reason = hasNamedExports ?
844+ "cannot be used with 'options.namedExports' or 'options.defaultExport'" :
845+ "cannot be used with 'options.defaultExport'" ;
846+ }
847+
848+ throw new ERR_INVALID_ARG_VALUE ( 'options.exports' , options . exports , reason ) ;
849+ }
850+
851+ if ( hasExports ) {
852+ copyOwnProperties ( options . exports , moduleExports ) ;
853+ }
854+
855+ if ( hasNamedExports ) {
856+ copyOwnProperties ( options . namedExports , moduleExports ) ;
857+ }
858+
859+ if ( hasDefaultExport ) {
860+ ObjectDefineProperty (
861+ moduleExports ,
862+ 'default' ,
863+ ObjectAssign ( { __proto__ : null } , ObjectGetOwnPropertyDescriptor ( options , 'defaultExport' ) ) ,
864+ ) ;
865+ }
866+
867+ return {
868+ __proto__ : null ,
869+ cache,
870+ moduleExports,
871+ } ;
872+ }
873+
874+
875+ function copyOwnProperties ( from , to ) {
876+ const keys = ObjectKeys ( from ) ;
877+
878+ for ( let i = 0 ; i < keys . length ; ++ i ) {
879+ const key = keys [ i ] ;
880+ const descriptor = ObjectGetOwnPropertyDescriptor ( from , key ) ;
881+ ObjectDefineProperty ( to , key , descriptor ) ;
882+ }
883+ }
884+
819885function setupSharedModuleState ( ) {
820886 if ( sharedModuleState === undefined ) {
821887 const { mock } = require ( 'test' ) ;
@@ -855,9 +921,7 @@ function cjsMockModuleLoad(request, parent, isMain) {
855921 const {
856922 cache,
857923 caller,
858- defaultExport,
859- hasDefaultExport,
860- namedExports,
924+ moduleExports,
861925 } = config ;
862926
863927 if ( cache && Module . _cache [ resolved ] ) {
@@ -866,9 +930,10 @@ function cjsMockModuleLoad(request, parent, isMain) {
866930 return Module . _cache [ resolved ] . exports ;
867931 }
868932
933+ const hasDefaultExport = 'default' in moduleExports ;
869934 // eslint-disable-next-line node-core/set-proto-to-null-in-object
870- const modExports = hasDefaultExport ? defaultExport : { } ;
871- const exportNames = ObjectKeys ( namedExports ) ;
935+ const modExports = hasDefaultExport ? moduleExports . default : { } ;
936+ const exportNames = ArrayPrototypeFilter ( ObjectKeys ( moduleExports ) , ( k ) => k !== 'default' ) ;
872937
873938 if ( ( typeof modExports !== 'object' || modExports === null ) &&
874939 exportNames . length > 0 ) {
@@ -878,7 +943,7 @@ function cjsMockModuleLoad(request, parent, isMain) {
878943
879944 for ( let i = 0 ; i < exportNames . length ; ++ i ) {
880945 const name = exportNames [ i ] ;
881- const descriptor = ObjectGetOwnPropertyDescriptor ( namedExports , name ) ;
946+ const descriptor = ObjectGetOwnPropertyDescriptor ( moduleExports , name ) ;
882947 ObjectDefineProperty ( modExports , name , descriptor ) ;
883948 }
884949
0 commit comments