From 2fcd2be17baa8c7d829bc98b551da1c67a8be558 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 2 Oct 2025 15:22:47 +0200 Subject: [PATCH 1/5] Automigration: Added support for transforming `defaultOrientation` and renaming `disable` to `disabled` in viewport stories --- .../fixes/addon-globals-api.test.ts | 38 +++++++++++++++++++ .../automigrate/fixes/addon-globals-api.ts | 24 +++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts index 7eb0ffc0b894..ec329294aba6 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts @@ -816,5 +816,43 @@ describe('addon-globals-api', () => { expect(transformFn).toBeDefined(); expect(transformFn!('story.js', storyContent)).toBe(expectedContent); }); + + it('should transform defaultOrientation and disabled properties in viewport stories', async () => { + const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview); + const storyContent = dedent` + import Button from './Button'; + export default { component: Button }; + export const Mobile = { + parameters: { + viewport: { + defaultOrientation: 'portrait', + defaultViewport: 'iphonex', + disable: true, + }, + }, + }; + `; + const expectedContent = dedent` + import Button from './Button'; + export default { + component: Button + }; + export const Mobile = { + parameters: { + viewport: { + disabled: true + } + }, + globals: { + viewport: { + value: "iphonex", + isRotated: true + } + } + }; + `; + expect(transformFn).toBeDefined(); + expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + }); }); }); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts index e7d59be0a7fd..a2c64472d473 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts @@ -310,18 +310,26 @@ function transformStoryFile( viewportParams = getObjectProperty(parameters, 'viewport') as ObjectExpression; if (viewportParams) { const defaultViewport = getObjectProperty(viewportParams, 'defaultViewport'); + const defaultOrientation = getObjectProperty(viewportParams, 'defaultOrientation'); + const disableViewport = getObjectProperty(viewportParams, 'disable'); if (defaultViewport && t.isStringLiteral(defaultViewport)) { // Create globals.viewport if (!newGlobals) { newGlobals = t.objectExpression([]); } + // Determine isRotated based on defaultOrientation + let isRotated = false; + if (defaultOrientation && t.isStringLiteral(defaultOrientation)) { + isRotated = defaultOrientation.value === 'portrait'; + } + newGlobals.properties.push( t.objectProperty( t.identifier('viewport'), t.objectExpression([ t.objectProperty(t.identifier('value'), t.stringLiteral(defaultViewport.value)), - t.objectProperty(t.identifier('isRotated'), t.booleanLiteral(false)), + t.objectProperty(t.identifier('isRotated'), t.booleanLiteral(isRotated)), ]) ) ); @@ -330,6 +338,20 @@ function transformStoryFile( removeProperty(viewportParams, 'defaultViewport'); storyHasChanges = true; } + + // Handle defaultOrientation removal + if (defaultOrientation) { + removeProperty(viewportParams, 'defaultOrientation'); + storyHasChanges = true; + } + + // Handle disable -> disabled rename + if (disableViewport && t.isBooleanLiteral(disableViewport)) { + removeProperty(viewportParams, 'disable'); + // Rename disable to disabled (preserve both true and false values) + addProperty(viewportParams, 'disabled', disableViewport); + storyHasChanges = true; + } } } From c4057f6d2efb4772230fafb64ed124cbeef756f5 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 2 Oct 2025 15:28:44 +0200 Subject: [PATCH 2/5] Automigration: Enhance viewport story transformation to support member expression references for `defaultViewport` --- .../fixes/addon-globals-api.test.ts | 33 +++++++++++++++++++ .../automigrate/fixes/addon-globals-api.ts | 16 +++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts index ec329294aba6..e2a0bbd5723b 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts @@ -854,5 +854,38 @@ describe('addon-globals-api', () => { expect(transformFn).toBeDefined(); expect(transformFn!('story.js', storyContent)).toBe(expectedContent); }); + + it('should transform member expression references in viewport stories', async () => { + const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview); + const storyContent = dedent` + import { MINIMAL_VIEWPORTS } from 'storybook/viewport'; + import Button from './Button'; + export default { component: Button }; + export const Mobile = { + parameters: { + viewport: { + defaultViewport: MINIMAL_VIEWPORTS.mobile2 + }, + }, + }; + `; + const expectedContent = dedent` + import { MINIMAL_VIEWPORTS } from 'storybook/viewport'; + import Button from './Button'; + export default { + component: Button + }; + export const Mobile = { + globals: { + viewport: { + value: MINIMAL_VIEWPORTS.mobile2, + isRotated: false + } + } + }; + `; + expect(transformFn).toBeDefined(); + expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + }); }); }); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts index a2c64472d473..fa1112761403 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts @@ -312,7 +312,19 @@ function transformStoryFile( const defaultViewport = getObjectProperty(viewportParams, 'defaultViewport'); const defaultOrientation = getObjectProperty(viewportParams, 'defaultOrientation'); const disableViewport = getObjectProperty(viewportParams, 'disable'); - if (defaultViewport && t.isStringLiteral(defaultViewport)) { + + // Handle both string literals and member expressions for defaultViewport + let viewportValue: t.StringLiteral | t.MemberExpression | null = null; + if (defaultViewport) { + if (t.isStringLiteral(defaultViewport)) { + viewportValue = defaultViewport; + } else if (t.isMemberExpression(defaultViewport)) { + // Preserve the member expression as-is + viewportValue = defaultViewport; + } + } + + if (viewportValue) { // Create globals.viewport if (!newGlobals) { newGlobals = t.objectExpression([]); @@ -328,7 +340,7 @@ function transformStoryFile( t.objectProperty( t.identifier('viewport'), t.objectExpression([ - t.objectProperty(t.identifier('value'), t.stringLiteral(defaultViewport.value)), + t.objectProperty(t.identifier('value'), viewportValue), t.objectProperty(t.identifier('isRotated'), t.booleanLiteral(isRotated)), ]) ) From e85e68af2da6f1997daaa717daa33badd572535f Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 2 Oct 2025 15:47:39 +0200 Subject: [PATCH 3/5] Automigration: Implement transformations for backgrounds parameters and enhance viewport handling in story files --- .../fixes/addon-globals-api.test.ts | 51 +++++++++++++++++-- .../automigrate/fixes/addon-globals-api.ts | 12 +++++ 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts index e2a0bbd5723b..6eda026bee3f 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts @@ -635,7 +635,7 @@ describe('addon-globals-api', () => { export const MobileOnly = { globals: { viewport: { - value: "mobile", + value: 'mobile', isRotated: false } } @@ -665,7 +665,7 @@ describe('addon-globals-api', () => { export const DarkMobile = { globals: { viewport: { - value: "mobile", + value: 'mobile', isRotated: false }, backgrounds: { @@ -804,7 +804,7 @@ describe('addon-globals-api', () => { }, globals: { viewport: { - value: "tablet", + value: 'tablet', isRotated: false }, backgrounds: { @@ -845,7 +845,7 @@ describe('addon-globals-api', () => { }, globals: { viewport: { - value: "iphonex", + value: 'iphonex', isRotated: true } } @@ -887,5 +887,48 @@ describe('addon-globals-api', () => { expect(transformFn).toBeDefined(); expect(transformFn!('story.js', storyContent)).toBe(expectedContent); }); + + it('should transform backgrounds values to options and migrate default in story files', async () => { + const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview); + const storyContent = dedent` + import Button from './Button'; + export default { component: Button }; + export const Mobile = { + parameters: { + backgrounds: { + default: 'Light', + values: [ + { name: 'Gray', value: '#CCC' }, + ], + }, + }, + }; + `; + const expectedContent = dedent` + import Button from './Button'; + export default { + component: Button + }; + export const Mobile = { + parameters: { + backgrounds: { + options: { + gray: { + name: 'Gray', + value: '#CCC' + } + } + } + }, + globals: { + backgrounds: { + value: "light" + } + } + }; + `; + expect(transformFn).toBeDefined(); + expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + }); }); }); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts index fa1112761403..a949ea7306a0 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts @@ -373,6 +373,18 @@ function transformStoryFile( if (backgroundsParams) { const defaultBackground = getObjectProperty(backgroundsParams, 'default'); const disableBackground = getObjectProperty(backgroundsParams, 'disable'); + const valuesBackground = getObjectProperty(backgroundsParams, 'values'); + + // Handle values -> options transformation + if (valuesBackground && t.isArrayExpression(valuesBackground)) { + // Transform values array to options object + const optionsObject = transformValuesToOptions(valuesBackground); + + // Remove the old values property + removeProperty(backgroundsParams, 'values'); + addProperty(backgroundsParams, 'options', optionsObject); + storyHasChanges = true; + } if (defaultBackground && t.isStringLiteral(defaultBackground)) { // Create globals.backgrounds From c56a9aac1a6120d02575690dd75e77e7707734c5 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 8 Oct 2025 10:31:29 +0200 Subject: [PATCH 4/5] Refactor addon-globals-api tests and migration logic to utilize printCsf and streamline story transformations --- .../fixes/addon-globals-api.test.ts | 524 +++++++++--------- .../automigrate/fixes/addon-globals-api.ts | 24 +- 2 files changed, 266 insertions(+), 282 deletions(-) diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts index 6eda026bee3f..250d0a60137e 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts @@ -3,11 +3,13 @@ import { join } from 'node:path'; import { afterEach, describe, expect, it, vi } from 'vitest'; +import { printCsf } from 'storybook/internal/csf-tools'; + // Import common to mock import dedent from 'ts-dedent'; // Import FixResult type -import { addonGlobalsApi, transformStoryFileSync } from './addon-globals-api'; +import { addonGlobalsApi, transformStoryFile } from './addon-globals-api'; // Mock fs/promises vi.mock('node:fs/promises', async () => import('../../../../../__mocks__/fs/promises')); @@ -44,10 +46,7 @@ const runMigrationAndGetTransformFn = async (previewContents: string) => { const result = await check(previewContents); const mockWriteFile = vi.mocked(fsp.writeFile); - let transformFn: ( - filePath: string, - content: string - ) => ReturnType = () => null; + let transformFn: (filePath: string, content: string) => string | null = () => null; let transformOptions: any; @@ -60,14 +59,15 @@ const runMigrationAndGetTransformFn = async (previewContents: string) => { } as any); if (result) { - // Create a transform function that uses the sync version + // Create a transform function that uses transformStoryFile + printCsf transformFn = (filePath: string, content: string) => { - return transformStoryFileSync(content, { + const transformed = transformStoryFile(content, { needsViewportMigration: result.needsViewportMigration, needsBackgroundsMigration: result.needsBackgroundsMigration, viewportsOptions: result.viewportsOptions, backgroundsOptions: result.backgroundsOptions, }); + return transformed ? printCsf(transformed, {}).code : null; }; // Extract options passed to transformStoryFile from the closure // This is a bit indirect, relying on the implementation detail @@ -245,25 +245,25 @@ describe('addon-globals-api', () => { } `); - expect(previewFileContent).toMatchInlineSnapshot(dedent` - "export default { - parameters: { - viewport: { - options: { - mobile: { name: 'Mobile', width: '320px', height: '568px' }, - tablet: { name: 'Tablet', width: '768px', height: '1024px' } - } - } - }, + expect(previewFileContent).toMatchInlineSnapshot(` + "export default { + parameters: { + viewport: { + options: { + mobile: { name: 'Mobile', width: '320px', height: '568px' }, + tablet: { name: 'Tablet', width: '768px', height: '1024px' } + } + } + }, - initialGlobals: { - viewport: { - value: 'mobile', - isRotated: false - } - } - };" -`); + initialGlobals: { + viewport: { + value: 'mobile', + isRotated: false + } + } + };" + `); }); it('should migrate backgrounds configuration correctly', async () => { @@ -281,24 +281,24 @@ describe('addon-globals-api', () => { } `); - expect(previewFileContent).toMatchInlineSnapshot(dedent` - "export default { - parameters: { - backgrounds: { - options: { - light: { name: 'Light', value: '#F8F8F8' }, - dark: { name: 'Dark', value: '#333333' } - } - } - }, + expect(previewFileContent).toMatchInlineSnapshot(` + "export default { + parameters: { + backgrounds: { + options: { + light: { name: 'Light', value: '#F8F8F8' }, + dark: { name: 'Dark', value: '#333333' } + } + } + }, - initialGlobals: { - backgrounds: { - value: 'light' - } - } - };" -`); + initialGlobals: { + backgrounds: { + value: 'light' + } + } + };" + `); }); it('should rename backgrounds disable property to disabled', async () => { @@ -316,7 +316,7 @@ describe('addon-globals-api', () => { `); // Verify the transformation results - expect(previewFileContent).toMatchInlineSnapshot(dedent` + expect(previewFileContent).toMatchInlineSnapshot(` "export default { parameters: { backgrounds: { @@ -351,7 +351,7 @@ describe('addon-globals-api', () => { } `); - expect(previewFileContent).toMatchInlineSnapshot(dedent` + expect(previewFileContent).toMatchInlineSnapshot(` "export default { parameters: { viewport: { @@ -400,7 +400,7 @@ describe('addon-globals-api', () => { `); // Verify the transformation results - expect(previewFileContent).toMatchInlineSnapshot(dedent` + expect(previewFileContent).toMatchInlineSnapshot(` "export default { parameters: { viewport: { @@ -439,33 +439,33 @@ describe('addon-globals-api', () => { } `); - expect(previewFileContent).toMatchInlineSnapshot(dedent` - "import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport'; + expect(previewFileContent).toMatchInlineSnapshot(` + "import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport'; - export default { - parameters: { - viewport: { - options: INITIAL_VIEWPORTS - }, - backgrounds: { - options: { - light: { name: 'Light', value: '#F8F8F8' }, - dark: { name: 'Dark', value: '#333333' } - } - } + export default { + parameters: { + viewport: { + options: INITIAL_VIEWPORTS }, + backgrounds: { + options: { + light: { name: 'Light', value: '#F8F8F8' }, + dark: { name: 'Dark', value: '#333333' } + } + } + }, - initialGlobals: { - viewport: { - value: 'tablet', - isRotated: false - }, + initialGlobals: { + viewport: { + value: 'tablet', + isRotated: false + }, - backgrounds: { - value: 'light' - } + backgrounds: { + value: 'light' } - };" + } + };" `); }); @@ -486,7 +486,7 @@ describe('addon-globals-api', () => { } `); - expect(previewFileContent).toMatchInlineSnapshot(dedent` + expect(previewFileContent).toMatchInlineSnapshot(` "export default { parameters: { backgrounds: { @@ -542,21 +542,18 @@ describe('addon-globals-api', () => { }; `; - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button - }; - export const Default = { - globals: { - backgrounds: { - value: "dark" - } - } - }; - `; expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + export default { component: Button }; + export const Default = { + globals: { + backgrounds: { + value: 'dark' + } + } + };" + `); }); it('should migrate parameters.backgrounds.disable: true to disabled: true', async () => { @@ -570,21 +567,16 @@ describe('addon-globals-api', () => { } }; `; - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button - }; - export const Disabled = { - parameters: { - backgrounds: { - disabled: true - } - } - }; - `; expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + export default { component: Button }; + export const Disabled = { + parameters: { + backgrounds: { disabled: true } + } + };" + `); }); it('should rename parameters.backgrounds.disable: false to disabled: false', async () => { @@ -598,22 +590,16 @@ describe('addon-globals-api', () => { } }; `; - // disable should be renamed to disabled - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button - }; - export const Disabled = { - parameters: { - backgrounds: { - disabled: false - } - } - }; - `; expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + export default { component: Button }; + export const Disabled = { + parameters: { + backgrounds: { disabled: false } + } + };" + `); }); it('should migrate parameters.viewport.defaultViewport to globals.viewport', async () => { @@ -627,22 +613,19 @@ describe('addon-globals-api', () => { } }; `; - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button - }; - export const MobileOnly = { - globals: { - viewport: { - value: 'mobile', - isRotated: false - } - } - }; - `; expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + export default { component: Button }; + export const MobileOnly = { + globals: { + viewport: { + value: 'mobile', + isRotated: false + } + } + };" + `); }); it('should migrate both viewport and backgrounds in the same story', async () => { @@ -657,25 +640,23 @@ describe('addon-globals-api', () => { } }; `; - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button - }; - export const DarkMobile = { - globals: { - viewport: { - value: 'mobile', - isRotated: false - }, - backgrounds: { - value: "dark" - } - } - }; - `; expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + export default { component: Button }; + export const DarkMobile = { + globals: { + viewport: { + value: 'mobile', + isRotated: false + }, + + backgrounds: { + value: 'dark' + } + } + };" + `); }); it('should handle migration in meta (export default)', async () => { @@ -696,7 +677,7 @@ describe('addon-globals-api', () => { component: Button, globals: { backgrounds: { - value: "tweet" + value: 'tweet' } } }; @@ -723,98 +704,131 @@ describe('addon-globals-api', () => { const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview); const storyContent = dedent` import Button from './Button'; - export default { component: Button }; - export const ExistingGlobals = { globals: { backgrounds: { value: 'dark' } } }; - export const NeedsMigration = { parameters: { backgrounds: { default: 'Dark' } } }; + + export default { + component: Button + }; + + export const ExistingGlobals = { + globals: { + backgrounds: { + value: 'dark' + } + } + }; + + export const NeedsMigration = { + parameters: { + backgrounds: { + default: 'Dark' + } + } + }; `; - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button + expect(transformFn).toBeDefined(); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + + export default { + component: Button }; - export const ExistingGlobals = { - globals: { - backgrounds: { - value: 'dark' - } - } + + export const ExistingGlobals = { + globals: { + backgrounds: { + value: 'dark' + } + } }; - export const NeedsMigration = { + + export const NeedsMigration = { globals: { backgrounds: { - value: "dark" + value: 'dark' } - } - }; - `; - expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + } + };" + `); }); it('should merge new globals with existing globals in the same story', async () => { const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview); const storyContent = dedent` import Button from './Button'; + export default { component: Button }; - export const ExistingAndNeedsMigration = { - globals: { backgrounds: { value: 'light' } }, - parameters: { backgrounds: { default: 'Dark' } } - }; - `; - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button - }; - export const ExistingAndNeedsMigration = { - globals: { + + export const ExistingAndNeedsMigration = { + globals: { + backgrounds: { + value: 'light' + } + }, + parameters: { backgrounds: { - value: 'light' + default: 'Dark' } - } + } }; `; expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + + export default { component: Button }; + + export const ExistingAndNeedsMigration = { + globals: { + backgrounds: { + value: 'light' + } + } + };" + `); }); it('should remove empty parameters/backgrounds/viewport objects after migration', async () => { const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview); const storyContent = dedent` import Button from './Button'; + export default { component: Button }; + export const TestStory = { parameters: { otherParam: true, - backgrounds: { default: 'Dark' }, // This will move - viewport: { defaultViewport: 'tablet' } // This will move - } - }; - `; - // parameters.backgrounds and parameters.viewport become empty and are removed - // parameters still has otherParam, so it remains - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button - }; - export const TestStory = { - parameters: { - otherParam: true - }, - globals: { - viewport: { - value: 'tablet', - isRotated: false + backgrounds: { + default: 'Dark' }, - backgrounds: { - value: "dark" + viewport: { + defaultViewport: 'tablet' } } }; `; expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + + export default { component: Button }; + + export const TestStory = { + parameters: { + otherParam: true + }, + + globals: { + viewport: { + value: 'tablet', + isRotated: false + }, + + backgrounds: { + value: 'dark' + } + } + };" + `); }); it('should transform defaultOrientation and disabled properties in viewport stories', async () => { @@ -832,27 +846,25 @@ describe('addon-globals-api', () => { }, }; `; - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button - }; - export const Mobile = { - parameters: { - viewport: { - disabled: true - } + expect(transformFn).toBeDefined(); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + export default { component: Button }; + export const Mobile = { + parameters: { + viewport: { + disabled: true }, - globals: { - viewport: { - value: 'iphonex', - isRotated: true - } + }, + + globals: { + viewport: { + value: 'iphonex', + isRotated: true } - }; - `; - expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + } + };" + `); }); it('should transform member expression references in viewport stories', async () => { @@ -869,23 +881,20 @@ describe('addon-globals-api', () => { }, }; `; - const expectedContent = dedent` - import { MINIMAL_VIEWPORTS } from 'storybook/viewport'; - import Button from './Button'; - export default { - component: Button - }; - export const Mobile = { - globals: { - viewport: { - value: MINIMAL_VIEWPORTS.mobile2, - isRotated: false - } - } - }; - `; expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import { MINIMAL_VIEWPORTS } from 'storybook/viewport'; + import Button from './Button'; + export default { component: Button }; + export const Mobile = { + globals: { + viewport: { + value: MINIMAL_VIEWPORTS.mobile2, + isRotated: false + } + }, + };" + `); }); it('should transform backgrounds values to options and migrate default in story files', async () => { @@ -904,31 +913,26 @@ describe('addon-globals-api', () => { }, }; `; - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button - }; - export const Mobile = { - parameters: { - backgrounds: { - options: { - gray: { - name: 'Gray', - value: '#CCC' - } - } + expect(transformFn).toBeDefined(); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + export default { component: Button }; + export const Mobile = { + parameters: { + backgrounds: { + options: { + gray: { name: 'Gray', value: '#CCC' } } }, - globals: { - backgrounds: { - value: "light" - } + }, + + globals: { + backgrounds: { + value: 'light' } - }; - `; - expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + } + };" + `); }); }); }); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts index a949ea7306a0..8fce0c320a86 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts @@ -2,13 +2,7 @@ import { readFile, writeFile } from 'node:fs/promises'; import { types as t } from 'storybook/internal/babel'; import type { ConfigFile, CsfFile } from 'storybook/internal/csf-tools'; -import { - formatConfig, - formatCsf, - loadConfig, - loadCsf, - writeCsf, -} from 'storybook/internal/csf-tools'; +import { formatConfig, loadConfig, loadCsf, writeCsf } from 'storybook/internal/csf-tools'; import type { ArrayExpression, Expression, ObjectExpression } from '@babel/types'; @@ -232,20 +226,6 @@ export const addonGlobalsApi: Fix = { }, }; -// Individual story transformation function for testing -export function transformStoryFileSync( - source: string, - options: { - needsViewportMigration: boolean; - needsBackgroundsMigration: boolean; - viewportsOptions: any; - backgroundsOptions: any; - } -) { - const result = transformStoryFile(source, options); - return result ? formatCsf(result, {}, source) : null; -} - // Story transformation function async function transformStoryFiles( files: string[], @@ -282,7 +262,7 @@ async function transformStoryFiles( } // Transform a single story file -function transformStoryFile( +export function transformStoryFile( source: string, options: { needsViewportMigration: boolean; From f740d75d8302cf87b81ddbd70047e5882bdef4ed Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 8 Oct 2025 11:00:11 +0200 Subject: [PATCH 5/5] Fix test for Windows --- .../fixes/addon-globals-api.test.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts index 250d0a60137e..01cab31471a3 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts @@ -671,20 +671,20 @@ describe('addon-globals-api', () => { }; export const Default = {}; `; - const expectedContent = dedent` - import Button from './Button'; - export default { - component: Button, - globals: { - backgrounds: { - value: 'tweet' - } - } - }; - export const Default = {}; - `; + expect(transformFn).toBeDefined(); - expect(transformFn!('story.js', storyContent)).toBe(expectedContent); + expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(` + "import Button from './Button'; + export default { + component: Button, + globals: { + backgrounds: { + value: 'tweet' + } + } + }; + export const Default = {};" + `); }); it('should return null if no changes are needed', async () => {