@@ -28,6 +28,24 @@ vi.mock('storybook/internal/cli', () => ({
28
28
getStorybookVersionSpecifier : vi . fn ( ) ,
29
29
} ) ) ;
30
30
31
+ vi . mock ( 'storybook/internal/common' , ( ) => ( {
32
+ getAddonNames : vi . fn ( ) ,
33
+ getProjectRoot : vi . fn ( ) . mockReturnValue ( '/fake/project/root' ) ,
34
+ commonGlobOptions : vi . fn ( ) . mockReturnValue ( { } ) ,
35
+ } ) ) ;
36
+
37
+ vi . mock ( 'prompts' , ( ) => ( {
38
+ default : vi . fn ( ) . mockResolvedValue ( { glob : '**/*.{mjs,cjs,js,jsx,ts,tsx,mdx}' } ) ,
39
+ } ) ) ;
40
+
41
+ vi . mock ( 'globby' , ( ) => ( {
42
+ globby : vi . fn ( ) . mockResolvedValue ( [ '/fake/project/root/src/stories/Button.stories.tsx' ] ) ,
43
+ } ) ) ;
44
+
45
+ vi . mock ( '../helpers/transformImports' , ( ) => ( {
46
+ transformImportFiles : vi . fn ( ) . mockResolvedValue ( [ ] ) ,
47
+ } ) ) ;
48
+
31
49
// Mock ConfigFile type
32
50
interface MockConfigFile {
33
51
getFieldValue : ( path : string [ ] ) => any ;
@@ -47,7 +65,10 @@ const mockConfigs = new Map<string, MockConfigFile>();
47
65
const readFileMock = vi . mocked ( await import ( 'node:fs/promises' ) ) . readFile ;
48
66
49
67
const mockPackageManager = {
50
- retrievePackageJson : vi . fn ( ) ,
68
+ retrievePackageJson : vi . fn ( ) . mockResolvedValue ( {
69
+ dependencies : { } ,
70
+ devDependencies : { } ,
71
+ } ) ,
51
72
runPackageCommand : vi . fn ( ) ,
52
73
} as unknown as JsPackageManager ;
53
74
@@ -70,6 +91,7 @@ interface AddonDocsOptions {
70
91
hasEssentials : boolean ;
71
92
hasDocsDisabled : boolean ;
72
93
hasDocsAddon : boolean ;
94
+ additionalAddonsToRemove : string [ ] ;
73
95
}
74
96
75
97
// Add type for migration object
@@ -92,7 +114,7 @@ describe('addon-essentials-remove-docs migration', () => {
92
114
expect ( result ) . toBeNull ( ) ;
93
115
} ) ;
94
116
95
- it ( 'returns null if essentials not found in config' , async ( ) => {
117
+ it ( 'returns null if essentials and no core addons found in config' , async ( ) => {
96
118
const mainConfig = `
97
119
export default {
98
120
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
@@ -112,13 +134,14 @@ describe('addon-essentials-remove-docs migration', () => {
112
134
expect ( result ) . toBeNull ( ) ;
113
135
} ) ;
114
136
115
- it ( 'detects essentials with docs disabled' , async ( ) => {
137
+ it ( 'detects essentials with docs disabled and core addons ' , async ( ) => {
116
138
const mockMain : MockConfigFile = {
117
139
getFieldValue : vi . fn ( ) . mockReturnValue ( [
118
140
{
119
141
name : '@storybook/addon-essentials' ,
120
142
options : { docs : false } ,
121
143
} ,
144
+ '@storybook/addon-actions' ,
122
145
] ) ,
123
146
setFieldValue : vi . fn ( ) ,
124
147
appendValueToArray : vi . fn ( ) ,
@@ -130,6 +153,23 @@ describe('addon-essentials-remove-docs migration', () => {
130
153
} ;
131
154
132
155
mockConfigs . set ( 'main.ts' , mockMain ) ;
156
+ vi . mocked ( await import ( 'storybook/internal/common' ) ) . getAddonNames . mockReturnValue ( [
157
+ '@storybook/addon-essentials' ,
158
+ '@storybook/addon-actions' ,
159
+ ] ) ;
160
+
161
+ const mockPackageJsonWithAddons = {
162
+ dependencies : {
163
+ '@storybook/addon-controls' : '^7.0.0' ,
164
+ } ,
165
+ devDependencies : {
166
+ '@storybook/addon-toolbars' : '^7.0.0' ,
167
+ } ,
168
+ } ;
169
+
170
+ vi . mocked ( mockPackageManager . retrievePackageJson ) . mockResolvedValueOnce (
171
+ mockPackageJsonWithAddons
172
+ ) ;
133
173
134
174
const result = await typedAddonDocsEssentials . check ( {
135
175
...baseCheckOptions ,
@@ -141,19 +181,25 @@ describe('addon-essentials-remove-docs migration', () => {
141
181
name : '@storybook/addon-essentials' ,
142
182
options : { docs : false } ,
143
183
} ,
184
+ '@storybook/addon-actions' ,
144
185
] ,
145
186
} as StorybookConfigRaw ,
146
187
} ) ;
147
188
expect ( result ) . toEqual ( {
148
189
hasEssentials : true ,
149
190
hasDocsDisabled : true ,
150
191
hasDocsAddon : false ,
192
+ additionalAddonsToRemove : [
193
+ '@storybook/addon-actions' ,
194
+ '@storybook/addon-controls' ,
195
+ '@storybook/addon-toolbars' ,
196
+ ] ,
151
197
} ) ;
152
198
} ) ;
153
199
154
- it ( 'detects essentials with docs enabled ' , async ( ) => {
200
+ it ( 'detects only core addons without essentials ' , async ( ) => {
155
201
const mockMain : MockConfigFile = {
156
- getFieldValue : vi . fn ( ) . mockReturnValue ( [ '@storybook/addon-essentials ' ] ) ,
202
+ getFieldValue : vi . fn ( ) . mockReturnValue ( [ '@storybook/addon-actions ' ] ) ,
157
203
setFieldValue : vi . fn ( ) ,
158
204
appendValueToArray : vi . fn ( ) ,
159
205
removeField : vi . fn ( ) ,
@@ -164,30 +210,46 @@ describe('addon-essentials-remove-docs migration', () => {
164
210
} ;
165
211
166
212
mockConfigs . set ( 'main.ts' , mockMain ) ;
213
+ vi . mocked ( await import ( 'storybook/internal/common' ) ) . getAddonNames . mockReturnValue ( [
214
+ '@storybook/addon-actions' ,
215
+ ] ) ;
216
+
217
+ const mockPackageJsonWithViewport = {
218
+ dependencies : { } ,
219
+ devDependencies : {
220
+ '@storybook/addon-viewport' : '^7.0.0' ,
221
+ } ,
222
+ } ;
223
+
224
+ vi . mocked ( mockPackageManager . retrievePackageJson ) . mockResolvedValueOnce (
225
+ mockPackageJsonWithViewport
226
+ ) ;
167
227
168
228
const result = await typedAddonDocsEssentials . check ( {
169
229
...baseCheckOptions ,
170
230
mainConfigPath : 'main.ts' ,
171
231
mainConfig : {
172
232
stories : [ '../src/**/*.stories.@(js|jsx|ts|tsx)' ] ,
173
- addons : [ '@storybook/addon-essentials ' ] ,
233
+ addons : [ '@storybook/addon-actions ' ] ,
174
234
} as StorybookConfigRaw ,
175
235
} ) ;
176
236
expect ( result ) . toEqual ( {
177
- hasEssentials : true ,
237
+ hasEssentials : false ,
178
238
hasDocsDisabled : false ,
179
239
hasDocsAddon : false ,
240
+ additionalAddonsToRemove : [ '@storybook/addon-actions' , '@storybook/addon-viewport' ] ,
180
241
} ) ;
181
242
} ) ;
182
243
} ) ;
183
244
184
245
describe ( 'run phase' , ( ) => {
185
- it ( 'removes essentials addon when docs is disabled' , async ( ) => {
246
+ it ( 'removes essentials addon and core addons when docs is disabled' , async ( ) => {
186
247
await typedAddonDocsEssentials . run ( {
187
248
result : {
188
249
hasEssentials : true ,
189
250
hasDocsDisabled : true ,
190
251
hasDocsAddon : false ,
252
+ additionalAddonsToRemove : [ '@storybook/addon-actions' , '@storybook/addon-controls' ] ,
191
253
} ,
192
254
packageManager : mockPackageManager ,
193
255
packageJson : mockPackageJson ,
@@ -199,31 +261,81 @@ describe('addon-essentials-remove-docs migration', () => {
199
261
'remove' ,
200
262
'@storybook/addon-essentials' ,
201
263
] ) ;
202
- expect ( mockPackageManager . runPackageCommand ) . toHaveBeenCalledTimes ( 1 ) ;
264
+ expect ( mockPackageManager . runPackageCommand ) . toHaveBeenCalledWith ( 'storybook' , [
265
+ 'remove' ,
266
+ '@storybook/addon-actions' ,
267
+ ] ) ;
268
+ expect ( mockPackageManager . runPackageCommand ) . toHaveBeenCalledWith ( 'storybook' , [
269
+ 'remove' ,
270
+ '@storybook/addon-controls' ,
271
+ ] ) ;
272
+ expect ( mockPackageManager . runPackageCommand ) . toHaveBeenCalledTimes ( 3 ) ;
203
273
} ) ;
204
274
205
- it ( 'removes essentials addon and installs addon-docs when docs is enabled' , async ( ) => {
275
+ it ( 'removes core addons without essentials' , async ( ) => {
276
+ const mockPackageManagerLocal = {
277
+ retrievePackageJson : vi . fn ( ) ,
278
+ runPackageCommand : vi . fn ( ) ,
279
+ } as unknown as JsPackageManager ;
280
+
206
281
await typedAddonDocsEssentials . run ( {
207
282
result : {
208
- hasEssentials : true ,
283
+ hasEssentials : false ,
209
284
hasDocsDisabled : false ,
210
285
hasDocsAddon : false ,
286
+ additionalAddonsToRemove : [ '@storybook/addon-actions' , '@storybook/addon-controls' ] ,
211
287
} ,
212
- packageManager : mockPackageManager ,
288
+ packageManager : mockPackageManagerLocal ,
213
289
packageJson : mockPackageJson ,
214
290
mainConfigPath : 'main.ts' ,
215
291
mainConfig : { } as StorybookConfigRaw ,
216
292
} ) ;
217
293
218
- expect ( mockPackageManager . runPackageCommand ) . toHaveBeenCalledWith ( 'storybook' , [
294
+ expect ( mockPackageManagerLocal . runPackageCommand ) . toHaveBeenCalledWith ( 'storybook' , [
219
295
'remove' ,
220
- '@storybook/addon-essentials ' ,
296
+ '@storybook/addon-actions ' ,
221
297
] ) ;
222
- expect ( mockPackageManager . runPackageCommand ) . toHaveBeenCalledWith ( 'storybook' , [
298
+ expect ( mockPackageManagerLocal . runPackageCommand ) . toHaveBeenCalledWith ( 'storybook' , [
299
+ 'remove' ,
300
+ '@storybook/addon-controls' ,
301
+ ] ) ;
302
+ expect ( mockPackageManagerLocal . runPackageCommand ) . toHaveBeenCalledWith ( 'storybook' , [
223
303
'add' ,
224
304
'@storybook/addon-docs' ,
225
305
] ) ;
226
- expect ( mockPackageManager . runPackageCommand ) . toHaveBeenCalledTimes ( 2 ) ;
306
+ expect ( mockPackageManagerLocal . runPackageCommand ) . toHaveBeenCalledTimes ( 3 ) ;
307
+ } ) ;
308
+
309
+ it ( 'handles import transformations' , async ( ) => {
310
+ const { transformImportFiles } = await import ( '../helpers/transformImports' ) ;
311
+
312
+ await typedAddonDocsEssentials . run ( {
313
+ result : {
314
+ hasEssentials : false ,
315
+ hasDocsDisabled : false ,
316
+ hasDocsAddon : false ,
317
+ additionalAddonsToRemove : [ '@storybook/addon-actions' , '@storybook/addon-controls' ] ,
318
+ } ,
319
+ packageManager : mockPackageManager ,
320
+ packageJson : mockPackageJson ,
321
+ mainConfigPath : 'main.ts' ,
322
+ mainConfig : { } as StorybookConfigRaw ,
323
+ } ) ;
324
+
325
+ expect ( transformImportFiles ) . toHaveBeenCalledWith (
326
+ [ '/fake/project/root/src/stories/Button.stories.tsx' ] ,
327
+ {
328
+ '@storybook/addon-actions' : 'storybook/actions' ,
329
+ '@storybook/addon-controls' : 'storybook/internal/controls' ,
330
+ '@storybook/addon-toolbars' : 'storybook/internal/toolbars' ,
331
+ '@storybook/addon-highlight' : 'storybook/highlight' ,
332
+ '@storybook/addon-measure' : 'storybook/measure' ,
333
+ '@storybook/addon-outline' : 'storybook/outline' ,
334
+ '@storybook/addon-backgrounds' : 'storybook/backgrounds' ,
335
+ '@storybook/addon-viewport' : 'storybook/viewport' ,
336
+ } ,
337
+ undefined
338
+ ) ;
227
339
} ) ;
228
340
229
341
it ( 'does nothing in dry run mode' , async ( ) => {
@@ -232,6 +344,7 @@ describe('addon-essentials-remove-docs migration', () => {
232
344
hasEssentials : true ,
233
345
hasDocsDisabled : false ,
234
346
hasDocsAddon : false ,
347
+ additionalAddonsToRemove : [ '@storybook/addon-actions' , '@storybook/addon-controls' ] ,
235
348
} ,
236
349
packageManager : mockPackageManager ,
237
350
packageJson : mockPackageJson ,
@@ -243,12 +356,13 @@ describe('addon-essentials-remove-docs migration', () => {
243
356
expect ( mockPackageManager . runPackageCommand ) . not . toHaveBeenCalled ( ) ;
244
357
} ) ;
245
358
246
- it ( 'handles missing essentials addon gracefully' , async ( ) => {
359
+ it ( 'handles missing essentials addon and no core addons gracefully' , async ( ) => {
247
360
await typedAddonDocsEssentials . run ( {
248
361
result : {
249
362
hasEssentials : false ,
250
363
hasDocsDisabled : false ,
251
364
hasDocsAddon : false ,
365
+ additionalAddonsToRemove : [ ] ,
252
366
} ,
253
367
packageManager : mockPackageManager ,
254
368
packageJson : mockPackageJson ,
0 commit comments