11import fs from 'fs' ;
22import cloneDeep from 'lodash.clonedeep' ;
3- import * as actionUtils from '@metamask/action-utils/dist/file-utils ' ;
3+ import * as actionUtils from '@metamask/action-utils' ;
44import {
55 ManifestDependencyFieldNames ,
66 ManifestFieldNames ,
77} from '@metamask/action-utils' ;
88import * as autoChangelog from '@metamask/auto-changelog' ;
9+ import glob from 'glob' ;
910import * as gitOps from './git-operations' ;
1011import {
1112 getMetadataForAllPackages ,
@@ -23,20 +24,7 @@ jest.mock('fs', () => ({
2324 } ,
2425} ) ) ;
2526
26- jest . mock ( 'glob' , ( ) => {
27- return (
28- _pattern : string ,
29- _options : Record < string , unknown > ,
30- callback : ( error : Error | null , results : string [ ] ) => unknown ,
31- ) => {
32- callback ( null , [
33- 'packages/dir1' ,
34- 'packages/dir2' ,
35- 'packages/dir3' ,
36- 'packages/someFile' ,
37- ] ) ;
38- } ;
39- } ) ;
27+ jest . mock ( 'glob' ) ;
4028
4129jest . mock ( '@metamask/action-utils/dist/file-utils' , ( ) => {
4230 const actualModule = jest . requireActual (
@@ -119,19 +107,98 @@ describe('package-operations', () => {
119107 ? { isDirectory : ( ) => false }
120108 : { isDirectory : ( ) => true } ;
121109 } ) as any ) ;
110+ } ) ;
111+
112+ it ( 'does not throw' , async ( ) => {
113+ ( glob as jest . MockedFunction < any > ) . mockImplementation (
114+ (
115+ _pattern : string ,
116+ _options : unknown ,
117+ callback : ( error : null , data : string [ ] ) => void ,
118+ ) =>
119+ callback ( null , [
120+ 'packages/dir1' ,
121+ 'packages/dir2' ,
122+ 'packages/dir3' ,
123+ 'packages/someFile' ,
124+ ] ) ,
125+ ) ;
122126
123127 jest
124128 . spyOn ( actionUtils , 'readJsonObjectFile' )
125129 . mockImplementation ( getMockReadJsonFile ( ) ) ;
126- } ) ;
127130
128- it ( 'does not throw' , async ( ) => {
129131 expect ( await getMetadataForAllPackages ( [ 'packages/*' ] ) ) . toStrictEqual ( {
130132 [ names [ 0 ] ] : getMockPackageMetadata ( 0 ) ,
131133 [ names [ 1 ] ] : getMockPackageMetadata ( 1 ) ,
132134 [ names [ 2 ] ] : getMockPackageMetadata ( 2 ) ,
133135 } ) ;
134136 } ) ;
137+
138+ it ( 'resolves recursive workspaces' , async ( ) => {
139+ ( glob as jest . MockedFunction < any > )
140+ . mockImplementationOnce (
141+ (
142+ _pattern : string ,
143+ _options : unknown ,
144+ callback : ( error : null , data : string [ ] ) => void ,
145+ ) => callback ( null , [ 'packages/dir1' ] ) ,
146+ )
147+ . mockImplementationOnce (
148+ (
149+ _pattern : string ,
150+ _options : unknown ,
151+ callback : ( error : null , data : string [ ] ) => void ,
152+ ) => callback ( null , [ 'packages/dir2' ] ) ,
153+ ) ;
154+
155+ jest
156+ . spyOn ( actionUtils , 'readJsonObjectFile' )
157+ . mockImplementationOnce ( async ( ) => ( {
158+ ...getMockManifest ( names [ 0 ] , version ) ,
159+ private : true ,
160+ workspaces : [ 'packages/*' ] ,
161+ } ) )
162+ . mockImplementationOnce ( async ( ) => getMockManifest ( names [ 1 ] , version ) ) ;
163+
164+ expect ( await getMetadataForAllPackages ( [ 'packages/*' ] ) ) . toStrictEqual ( {
165+ [ names [ 0 ] ] : {
166+ ...getMockPackageMetadata ( 0 ) ,
167+ manifest : {
168+ ...getMockManifest ( names [ 0 ] , version ) ,
169+ private : true ,
170+ workspaces : [ 'packages/*' ] ,
171+ } ,
172+ } ,
173+ [ names [ 1 ] ] : {
174+ ...getMockPackageMetadata ( 1 ) ,
175+ dirPath : 'packages/dir1/packages/dir2' ,
176+ } ,
177+ } ) ;
178+ } ) ;
179+
180+ it ( 'throws if a sub-workspace does not have a name' , async ( ) => {
181+ ( glob as jest . MockedFunction < any > ) . mockImplementationOnce (
182+ (
183+ _pattern : string ,
184+ _options : unknown ,
185+ callback : ( error : null , data : string [ ] ) => void ,
186+ ) => callback ( null , [ 'packages/dir1' ] ) ,
187+ ) ;
188+
189+ jest
190+ . spyOn ( actionUtils , 'readJsonObjectFile' )
191+ . mockImplementationOnce ( async ( ) => ( {
192+ ...getMockManifest ( names [ 0 ] , version ) ,
193+ private : true ,
194+ workspaces : [ 'packages/*' ] ,
195+ name : undefined ,
196+ } ) ) ;
197+
198+ await expect ( getMetadataForAllPackages ( [ 'packages/*' ] ) ) . rejects . toThrow (
199+ 'Expected sub-workspace in "packages/dir1" to have a name.' ,
200+ ) ;
201+ } ) ;
135202 } ) ;
136203
137204 describe ( 'getPackagesToUpdate' , ( ) => {
@@ -313,6 +380,42 @@ describe('package-operations', () => {
313380 ) ;
314381 } ) ;
315382
383+ it ( 'does not throw if the file cannot be found' , async ( ) => {
384+ const originalVersion = '1.0.0' ;
385+ const newVersion = '1.0.1' ;
386+ const dir = mockDirs [ 0 ] ;
387+ const name = packageNames [ 0 ] ;
388+ const manifest = getMockManifest ( name , originalVersion ) ;
389+
390+ readFileMock . mockImplementationOnce ( async ( ) => {
391+ const error = new Error ( 'readError' ) ;
392+ ( error as any ) . code = 'ENOENT' ;
393+
394+ throw error ;
395+ } ) ;
396+
397+ const packageMetadata = getMockPackageMetadata ( dir , manifest ) ;
398+ const updateSpecification = {
399+ newVersion,
400+ packagesToUpdate : new Set ( packageNames ) ,
401+ repositoryUrl : 'https://fake' ,
402+ shouldUpdateChangelog : true ,
403+ synchronizeVersions : false ,
404+ } ;
405+
406+ const consoleWarnSpy = jest
407+ . spyOn ( console , 'warn' )
408+ . mockImplementationOnce ( ( ) => undefined ) ;
409+
410+ await updatePackage ( packageMetadata , updateSpecification ) ;
411+
412+ expect ( updateChangelogMock ) . not . toHaveBeenCalled ( ) ;
413+ expect ( consoleWarnSpy ) . toHaveBeenCalledTimes ( 1 ) ;
414+ expect ( consoleWarnSpy ) . toHaveBeenCalledWith (
415+ expect . stringMatching ( / ^ F a i l e d t o r e a d c h a n g e l o g / u) ,
416+ ) ;
417+ } ) ;
418+
316419 it ( 'throws if updated changelog is empty' , async ( ) => {
317420 const originalVersion = '1.0.0' ;
318421 const newVersion = '1.0.1' ;
0 commit comments