From 305f3fad61cc240969be882f7ab35b029d89a956 Mon Sep 17 00:00:00 2001 From: Reuben Ellis Date: Mon, 3 Jun 2024 06:58:26 -0600 Subject: [PATCH 1/7] Add fallback type for Storybook 6 builder syntax --- node-src/lib/getPrebuiltStorybookMetadata.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/node-src/lib/getPrebuiltStorybookMetadata.ts b/node-src/lib/getPrebuiltStorybookMetadata.ts index 9423b0724..fe01aea2e 100644 --- a/node-src/lib/getPrebuiltStorybookMetadata.ts +++ b/node-src/lib/getPrebuiltStorybookMetadata.ts @@ -12,7 +12,7 @@ import { viewLayers } from './viewLayers'; export interface SBProjectJson { addons: Record; - builder?: string; + builder?: string | { name: string }; framework: { name: string; }; @@ -22,15 +22,23 @@ export interface SBProjectJson { const getBuilder = (sbProjectJson: SBProjectJson): { name: string; packageVersion: string } => { const { builder, storybookPackages, storybookVersion } = sbProjectJson; - return builder - ? { + switch (typeof builder) { + case 'string': + return { name: builder, packageVersion: storybookPackages[builders[builder]].version, - } - : { + }; + case 'object': + return { + name: builder.name, + packageVersion: storybookPackages[builders[builder.name]].version, + }; + default: + return { name: 'webpack4', // the default builder for Storybook v6 packageVersion: storybookVersion, }; + } }; export const getStorybookMetadataFromProjectJson = async ( From 2ab4b8c0a8d0d01968564826c75f8251b74778ec Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Mon, 3 Jun 2024 15:17:13 +0200 Subject: [PATCH 2/7] More reliable builder name logic --- node-src/lib/getPrebuiltStorybookMetadata.ts | 21 ++++---------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/node-src/lib/getPrebuiltStorybookMetadata.ts b/node-src/lib/getPrebuiltStorybookMetadata.ts index fe01aea2e..6c9a869b7 100644 --- a/node-src/lib/getPrebuiltStorybookMetadata.ts +++ b/node-src/lib/getPrebuiltStorybookMetadata.ts @@ -22,23 +22,10 @@ export interface SBProjectJson { const getBuilder = (sbProjectJson: SBProjectJson): { name: string; packageVersion: string } => { const { builder, storybookPackages, storybookVersion } = sbProjectJson; - switch (typeof builder) { - case 'string': - return { - name: builder, - packageVersion: storybookPackages[builders[builder]].version, - }; - case 'object': - return { - name: builder.name, - packageVersion: storybookPackages[builders[builder.name]].version, - }; - default: - return { - name: 'webpack4', // the default builder for Storybook v6 - packageVersion: storybookVersion, - }; - } + const name = typeof builder === 'string' ? builder : builder?.name; + return name + ? { name, packageVersion: storybookPackages[builders[name]]?.version } + : { name: 'webpack4', packageVersion: storybookVersion }; // the default builder for Storybook v6 }; export const getStorybookMetadataFromProjectJson = async ( From 19be0cd13a36e642aaa172d8e36ce2081524ea61 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Mon, 3 Jun 2024 18:55:15 +0200 Subject: [PATCH 3/7] Formatting --- bin-src/init.test.ts | 210 +++++++++++++++++++++++++------------------ 1 file changed, 121 insertions(+), 89 deletions(-) diff --git a/bin-src/init.test.ts b/bin-src/init.test.ts index afbeb2998..bbab15a3b 100644 --- a/bin-src/init.test.ts +++ b/bin-src/init.test.ts @@ -1,102 +1,134 @@ -import { execaCommand } from "execa" -import { writeFile } from "jsonfile"; -import { afterEach, describe, expect, it, vi } from "vitest"; +import { execaCommand } from 'execa'; +import { writeFile } from 'jsonfile'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { addChromaticScriptToPackageJson, createChromaticConfigFile, installArchiveDependencies } from "./init"; -import { beforeEach } from "node:test"; +import { + addChromaticScriptToPackageJson, + createChromaticConfigFile, + installArchiveDependencies, +} from './init'; vi.mock('jsonfile', async (importOriginal) => { - return { - // @ts-expect-error TS does not think actual is an object, but it's fine. - ...await importOriginal(), - writeFile: vi.fn(() => Promise.resolve()), - }; + return { + // @ts-expect-error TS does not think actual is an object, but it's fine. + ...(await importOriginal()), + writeFile: vi.fn(() => Promise.resolve()), + }; }); vi.mock('execa'); describe('addChromaticScriptToPackageJson', () => { - afterEach(() => { - vi.restoreAllMocks() - }) - it('outputs updated package.json with only chromatic script if Framework is Storybook', async () => { - await addChromaticScriptToPackageJson({ - packageJson: {}, - packagePath: './package.json' - }) - expect(writeFile).toHaveBeenCalledOnce() - expect(writeFile).toHaveBeenCalledWith('./package.json', { - scripts: { - chromatic: `chromatic` - } - }, { spaces: 2 }) - }) + afterEach(() => { + vi.restoreAllMocks(); + }); + it('outputs updated package.json with only chromatic script if Framework is Storybook', async () => { + await addChromaticScriptToPackageJson({ + packageJson: {}, + packagePath: './package.json', + }); + expect(writeFile).toHaveBeenCalledOnce(); + expect(writeFile).toHaveBeenCalledWith( + './package.json', + { + scripts: { + chromatic: `chromatic`, + }, + }, + { spaces: 2 } + ); + }); - it('outputs updated package.json with e2e script if Framework is not Storybook', async () => { - await addChromaticScriptToPackageJson({ - packageJson: {}, - packagePath: './package.json' - }) - expect(writeFile).toHaveBeenCalledOnce() - expect(writeFile).toHaveBeenCalledWith('./package.json', { - scripts: { - chromatic: `chromatic` - } - }, { spaces: 2 }) - }) -}) + it('outputs updated package.json with e2e script if Framework is not Storybook', async () => { + await addChromaticScriptToPackageJson({ + packageJson: {}, + packagePath: './package.json', + }); + expect(writeFile).toHaveBeenCalledOnce(); + expect(writeFile).toHaveBeenCalledWith( + './package.json', + { + scripts: { + chromatic: `chromatic`, + }, + }, + { spaces: 2 } + ); + }); +}); describe('createChromaticConfigFile', () => { - it('outputs file without buildScriptName when not passed one', async () => { - await createChromaticConfigFile({configFile: 'chromatic.config.json'}) - expect(writeFile).toHaveBeenCalledOnce() - expect(writeFile).toHaveBeenCalledWith('chromatic.config.json', {}) - }) -}) + it('outputs file without buildScriptName when not passed one', async () => { + await createChromaticConfigFile({ configFile: 'chromatic.config.json' }); + expect(writeFile).toHaveBeenCalledOnce(); + expect(writeFile).toHaveBeenCalledWith('chromatic.config.json', {}); + }); +}); describe('installArchiveDependencies', () => { - beforeEach(() => { - vi.doMock('find-up', async () => { - return { - findUp: vi.fn(() => Promise.resolve(undefined)), - }; - }); - }) - afterEach(() => { - vi.clearAllMocks() - vi.resetModules() - }) - it('successfully installs list of dependencies for Playwright if SB package is not found and Essentials is not found', async () => { - await installArchiveDependencies({}, 'playwright') - expect(execaCommand).toHaveBeenCalledOnce() - expect(execaCommand).toHaveBeenCalledWith('yarn add -D chromatic @chromatic-com/playwright storybook@latest @storybook/addon-essentials@latest @storybook/server-webpack5@latest') - }) - it('successfully installs list of dependencies for Cypress if SB package is not found and Essentials is not found', async () => { - await installArchiveDependencies({}, 'cypress') - expect(execaCommand).toHaveBeenCalledOnce() - expect(execaCommand).toHaveBeenCalledWith('yarn add -D chromatic @chromatic-com/cypress storybook@latest @storybook/addon-essentials@latest @storybook/server-webpack5@latest') - }) - it('successfully installs list of dependencies if SB package is found and Essentials is not found', async () => { - await installArchiveDependencies({devDependencies: {'storybook': '7.6.5'}}, 'playwright') - expect(execaCommand).toHaveBeenCalledOnce() - expect(execaCommand).toHaveBeenCalledWith('yarn add -D chromatic @chromatic-com/playwright @storybook/addon-essentials@7.6.5 @storybook/server-webpack5@7.6.5') - }) - it('successfully installs list of dependencies if SB package is found and Essentials is found in devDependencies', async () => { - await installArchiveDependencies({devDependencies: {storybook: '7.6.5', '@storybook/addon-essentials': '7.6.5'}}, 'playwright') - expect(execaCommand).toHaveBeenCalledOnce() - expect(execaCommand).toHaveBeenCalledWith('yarn add -D chromatic @chromatic-com/playwright @storybook/server-webpack5@7.6.5') - vi.clearAllMocks() - }) - it('successfully installs list of dependencies if SB package is found and Essentials is found in dependencies', async () => { - await installArchiveDependencies({dependencies: {storybook: '7.6.5', '@storybook/addon-essentials': '7.6.5'}}, 'playwright') - expect(execaCommand).toHaveBeenCalledOnce() - expect(execaCommand).toHaveBeenCalledWith('yarn add -D chromatic @chromatic-com/playwright @storybook/server-webpack5@7.6.5') - vi.clearAllMocks() - }) - it('successfully installs list of dependencies if SB package is not found and Essentials is found in dependencies', async () => { - await installArchiveDependencies({dependencies: {'@storybook/addon-essentials': '7.6.5'}}, 'playwright') - expect(execaCommand).toHaveBeenCalledOnce() - expect(execaCommand).toHaveBeenCalledWith('yarn add -D chromatic @chromatic-com/playwright storybook@7.6.5 @storybook/server-webpack5@7.6.5') - vi.clearAllMocks() - }) -}) \ No newline at end of file + beforeEach(() => { + vi.doMock('find-up', async () => { + return { + findUp: vi.fn(() => Promise.resolve(undefined)), + }; + }); + }); + afterEach(() => { + vi.clearAllMocks(); + vi.resetModules(); + }); + it('successfully installs list of dependencies for Playwright if SB package is not found and Essentials is not found', async () => { + await installArchiveDependencies({}, 'playwright'); + expect(execaCommand).toHaveBeenCalledOnce(); + expect(execaCommand).toHaveBeenCalledWith( + 'yarn add -D chromatic @chromatic-com/playwright storybook@latest @storybook/addon-essentials@latest @storybook/server-webpack5@latest' + ); + }); + it('successfully installs list of dependencies for Cypress if SB package is not found and Essentials is not found', async () => { + await installArchiveDependencies({}, 'cypress'); + expect(execaCommand).toHaveBeenCalledOnce(); + expect(execaCommand).toHaveBeenCalledWith( + 'yarn add -D chromatic @chromatic-com/cypress storybook@latest @storybook/addon-essentials@latest @storybook/server-webpack5@latest' + ); + }); + it('successfully installs list of dependencies if SB package is found and Essentials is not found', async () => { + await installArchiveDependencies({ devDependencies: { storybook: '7.6.5' } }, 'playwright'); + expect(execaCommand).toHaveBeenCalledOnce(); + expect(execaCommand).toHaveBeenCalledWith( + 'yarn add -D chromatic @chromatic-com/playwright @storybook/addon-essentials@7.6.5 @storybook/server-webpack5@7.6.5' + ); + }); + it('successfully installs list of dependencies if SB package is found and Essentials is found in devDependencies', async () => { + await installArchiveDependencies( + { devDependencies: { storybook: '7.6.5', '@storybook/addon-essentials': '7.6.5' } }, + 'playwright' + ); + expect(execaCommand).toHaveBeenCalledOnce(); + expect(execaCommand).toHaveBeenCalledWith( + 'yarn add -D chromatic @chromatic-com/playwright @storybook/server-webpack5@7.6.5' + ); + vi.clearAllMocks(); + }); + it('successfully installs list of dependencies if SB package is found and Essentials is found in dependencies', async () => { + await installArchiveDependencies( + { dependencies: { storybook: '7.6.5', '@storybook/addon-essentials': '7.6.5' } }, + 'playwright' + ); + expect(execaCommand).toHaveBeenCalledOnce(); + expect(execaCommand).toHaveBeenCalledWith( + 'yarn add -D chromatic @chromatic-com/playwright @storybook/server-webpack5@7.6.5' + ); + vi.clearAllMocks(); + }); + it('successfully installs list of dependencies if SB package is not found and Essentials is found in dependencies', async () => { + await installArchiveDependencies( + { dependencies: { '@storybook/addon-essentials': '7.6.5' } }, + 'playwright' + ); + expect(execaCommand).toHaveBeenCalledOnce(); + expect(execaCommand).toHaveBeenCalledWith( + 'yarn add -D chromatic @chromatic-com/playwright storybook@7.6.5 @storybook/server-webpack5@7.6.5' + ); + vi.clearAllMocks(); + }); +}); From 3148c4273ed2d894d0f42516220157a141915649 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Mon, 3 Jun 2024 19:02:58 +0200 Subject: [PATCH 4/7] Add test --- .../lib/getPrebuiltStorybookMetadata.test.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 node-src/lib/getPrebuiltStorybookMetadata.test.ts diff --git a/node-src/lib/getPrebuiltStorybookMetadata.test.ts b/node-src/lib/getPrebuiltStorybookMetadata.test.ts new file mode 100644 index 000000000..dfa1874c8 --- /dev/null +++ b/node-src/lib/getPrebuiltStorybookMetadata.test.ts @@ -0,0 +1,61 @@ +import { getStorybookMetadataFromProjectJson } from './getPrebuiltStorybookMetadata'; + +import { readFile } from 'jsonfile'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +afterEach(() => { + vi.restoreAllMocks(); +}); + +vi.mock('jsonfile', async (importOriginal) => { + return { + // @ts-expect-error TS does not think actual is an object, but it's fine. + ...(await importOriginal()), + readFile: vi.fn(() => + Promise.resolve({ + addons: { + '@storybook/addon-essentials': { version: '8.1.0' }, + '@storybook/addon-links': { version: '8.1.0' }, + }, + builder: 'webpack5', + framework: { name: 'react' }, + storybookVersion: '8.1.0', + storybookPackages: { + '@storybook/react': { version: '8.1.0' }, + '@storybook/builder-webpack5': { version: '8.1.0' }, + '@storybook/addon-essentials': { version: '8.1.0' }, + '@storybook/addon-links': { version: '8.1.0' }, + }, + }) + ), + }; +}); + +describe('getStorybookMetadataFromProjectJson', () => { + it('should return the metadata from the project.json file', async () => { + const projectJsonPath = 'path/to/project.json'; + const metadata = await getStorybookMetadataFromProjectJson(projectJsonPath); + + expect(metadata).toEqual({ + viewLayer: 'react', + version: '8.1.0', + builder: { + name: 'webpack5', + packageVersion: '8.1.0', + }, + addons: [ + { + name: 'essentials', + packageName: '@storybook/addon-essentials', + packageVersion: '8.1.0', + }, + { + name: 'links', + packageName: '@storybook/addon-links', + packageVersion: '8.1.0', + }, + ], + }); + expect(readFile).toHaveBeenCalledWith(projectJsonPath); + }); +}); From 87addb45e9446d722fa9888fb5a033585907f8ed Mon Sep 17 00:00:00 2001 From: Reuben Ellis Date: Mon, 3 Jun 2024 11:28:21 -0600 Subject: [PATCH 5/7] Update Storybook metadata to account for sb6 through 8 --- .../__mocks__/normalProjectJson/project.json | 2 +- bin-src/__mocks__/sb6ProjectJson/project.json | 66 +++++++++++++++++++ node-src/lib/getStorybookInfo.test.ts | 45 ++++++++++++- node-src/lib/getStorybookMetadata.ts | 6 +- 4 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 bin-src/__mocks__/sb6ProjectJson/project.json diff --git a/bin-src/__mocks__/normalProjectJson/project.json b/bin-src/__mocks__/normalProjectJson/project.json index 6e8c74666..6bb371657 100644 --- a/bin-src/__mocks__/normalProjectJson/project.json +++ b/bin-src/__mocks__/normalProjectJson/project.json @@ -8,7 +8,7 @@ "packageManager": { "type": "yarn", "version": "1.22.19" }, "typescriptOptions": { "reactDocgen": "react-docgen-typescript" }, "preview": { "usesGlobals": false }, - "framework": { "name": "@storybook/react-webpack5", "options": {} }, + "framework": { "name": "@storybook/react-webpack5", "options": {}, "version": "8.1.5" }, "builder": "@storybook/builder-webpack5", "renderer": "@storybook/react", "storybookVersion": "8.1.5", diff --git a/bin-src/__mocks__/sb6ProjectJson/project.json b/bin-src/__mocks__/sb6ProjectJson/project.json new file mode 100644 index 000000000..2f9c377ff --- /dev/null +++ b/bin-src/__mocks__/sb6ProjectJson/project.json @@ -0,0 +1,66 @@ +{ + "generatedAt": 1717341501873, + "builder": { + "name": "webpack4" + }, + "hasCustomBabel": false, + "hasCustomWebpack": true, + "hasStaticDirs": true, + "hasStorybookEslint": false, + "refCount": 0, + "monorepo": "Turborepo", + "packageManager": { + "type": "yarn", + "version": "1.22.19" + }, + "features": { + "postcss": false, + "interactionsDebugger": true, + "warnOnLegacyHierarchySeparator": false + }, + "storybookVersion": "6.5.16", + "language": "javascript", + "storybookPackages": { + "@storybook/addon-actions": { + "version": "6.5.16" + }, + "@storybook/addons": { + "version": "6.5.16" + }, + "@storybook/builder-webpack4": { + "version": "6.5.16" + }, + "@storybook/manager-webpack4": { + "version": "6.5.16" + }, + "@storybook/react": { + "version": "6.5.16" + }, + "@storybook/testing-library": { + "version": "0.0.13" + }, + "@storybook/theming": { + "version": "6.5.16" + }, + "msw-storybook-addon": { + "version": "1.7.0" + }, + "storybook-mock-date-decorator": { + "version": "1.0.0" + } + }, + "framework": { + "name": "react" + }, + "addons": { + "@storybook/addon-links": { + "version": "6.5.16" + }, + "@storybook/addon-essentials": { + "version": "6.5.16" + }, + "@storybook/addon-interactions": { + "version": "6.5.16" + } + } +} diff --git a/node-src/lib/getStorybookInfo.test.ts b/node-src/lib/getStorybookInfo.test.ts index f349acd9c..2abbb1a86 100644 --- a/node-src/lib/getStorybookInfo.test.ts +++ b/node-src/lib/getStorybookInfo.test.ts @@ -64,10 +64,12 @@ describe('getStorybookInfo', () => { { name: 'essentials', packageName: '@storybook/addon-essentials', + packageVersion: expect.any(String), }, { name: 'compiler-swc', packageName: '@storybook/addon-webpack5-compiler-swc', + packageVersion: expect.any(String), }, ], builder: { name: '@storybook/react-webpack5', packageVersion: '8.1.5' }, @@ -80,7 +82,19 @@ describe('getStorybookInfo', () => { // We're getting the result of tracing chromatic-cli's node_modules here. expect.objectContaining({ viewLayer: 'react', - version: expect.any(String), + version: '8.1.5', + addons: expect.arrayContaining([ + expect.objectContaining({ + name: 'essentials', + packageName: '@storybook/addon-essentials', + packageVersion: expect.any(String), + }), + expect.objectContaining({ + name: 'compiler-swc', + packageName: '@storybook/addon-webpack5-compiler-swc', + packageVersion: expect.any(String), + }), + ]), builder: { name: '@storybook/react-webpack5', packageVersion: '8.1.5' }, }) ); @@ -214,5 +228,34 @@ describe('getStorybookInfo', () => { viewLayer: '@storybook/react-webpack5', }); }); + + it('returns the correct metadata for Storybook 6', async () => { + const ctx = getContext({ + options: { storybookBuildDir: 'bin-src/__mocks__/sb6ProjectJson' }, + packageJson: { dependencies: REACT }, + }); + expect(await getStorybookInfo(ctx)).toEqual({ + addons: [ + { + name: 'links', + packageName: '@storybook/addon-links', + packageVersion: '6.5.16', + }, + { + name: 'essentials', + packageName: '@storybook/addon-essentials', + packageVersion: '6.5.16', + }, + { + name: 'interactions', + packageName: '@storybook/addon-interactions', + packageVersion: '6.5.16', + }, + ], + builder: { name: 'webpack4', packageVersion: '6.5.16' }, + version: '6.5.16', + viewLayer: 'react', + }); + }); }); }); diff --git a/node-src/lib/getStorybookMetadata.ts b/node-src/lib/getStorybookMetadata.ts index d2eae25ca..44838f8ab 100644 --- a/node-src/lib/getStorybookMetadata.ts +++ b/node-src/lib/getStorybookMetadata.ts @@ -134,7 +134,7 @@ const findAddons = async (ctx, mainConfig, v7) => { return { name: supportedAddons[name], packageName: name, - packageVersion: allDependencies[name], + packageVersion: allDependencies[name] || addon.version, }; }), }; @@ -204,15 +204,19 @@ export const findStorybookConfigFile = async (ctx: Context, pattern: RegExp) => export const getStorybookMetadata = async (ctx: Context) => { const configDir = ctx.options.storybookConfigDir ?? '.storybook'; + console.log(configDir); const r = typeof __non_webpack_require__ !== 'undefined' ? __non_webpack_require__ : require; let mainConfig; let v7 = false; try { mainConfig = await r(path.resolve(configDir, 'main')); + console.log(mainConfig); } catch (storybookV6error) { + console.log(storybookV6error); try { mainConfig = await readConfig(await findStorybookConfigFile(ctx, /^main\.[jt]sx?$/)); + console.log(mainConfig); v7 = true; } catch (storybookV7error) { mainConfig = null; From e8938a1a861f5a318aef08aed4b1bc3e85f361d5 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Mon, 3 Jun 2024 19:41:35 +0200 Subject: [PATCH 6/7] Avoid console.log --- node-src/lib/getStorybookMetadata.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/node-src/lib/getStorybookMetadata.ts b/node-src/lib/getStorybookMetadata.ts index 44838f8ab..e308df8e3 100644 --- a/node-src/lib/getStorybookMetadata.ts +++ b/node-src/lib/getStorybookMetadata.ts @@ -204,21 +204,21 @@ export const findStorybookConfigFile = async (ctx: Context, pattern: RegExp) => export const getStorybookMetadata = async (ctx: Context) => { const configDir = ctx.options.storybookConfigDir ?? '.storybook'; - console.log(configDir); const r = typeof __non_webpack_require__ !== 'undefined' ? __non_webpack_require__ : require; let mainConfig; let v7 = false; try { mainConfig = await r(path.resolve(configDir, 'main')); - console.log(mainConfig); + ctx.log.debug({ configDir, mainConfig }); } catch (storybookV6error) { - console.log(storybookV6error); + ctx.log.debug({ storybookV6error }); try { mainConfig = await readConfig(await findStorybookConfigFile(ctx, /^main\.[jt]sx?$/)); - console.log(mainConfig); + ctx.log.debug({ configDir, mainConfig }); v7 = true; } catch (storybookV7error) { + ctx.log.debug({ storybookV7error }); mainConfig = null; } } From 9483a03d56cf66da9f4794dc17c0a303390f54ec Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Mon, 3 Jun 2024 20:11:35 +0200 Subject: [PATCH 7/7] Extend tests --- .../sb6ProjectJsonMissingBuilder/project.json | 63 +++++++++++ .../lib/getPrebuiltStorybookMetadata.test.ts | 106 ++++++++++++------ 2 files changed, 132 insertions(+), 37 deletions(-) create mode 100644 bin-src/__mocks__/sb6ProjectJsonMissingBuilder/project.json diff --git a/bin-src/__mocks__/sb6ProjectJsonMissingBuilder/project.json b/bin-src/__mocks__/sb6ProjectJsonMissingBuilder/project.json new file mode 100644 index 000000000..227b6a4e4 --- /dev/null +++ b/bin-src/__mocks__/sb6ProjectJsonMissingBuilder/project.json @@ -0,0 +1,63 @@ +{ + "generatedAt": 1717341501873, + "hasCustomBabel": false, + "hasCustomWebpack": true, + "hasStaticDirs": true, + "hasStorybookEslint": false, + "refCount": 0, + "monorepo": "Turborepo", + "packageManager": { + "type": "yarn", + "version": "1.22.19" + }, + "features": { + "postcss": false, + "interactionsDebugger": true, + "warnOnLegacyHierarchySeparator": false + }, + "storybookVersion": "6.5.16", + "language": "javascript", + "storybookPackages": { + "@storybook/addon-actions": { + "version": "6.5.16" + }, + "@storybook/addons": { + "version": "6.5.16" + }, + "@storybook/builder-webpack4": { + "version": "6.5.16" + }, + "@storybook/manager-webpack4": { + "version": "6.5.16" + }, + "@storybook/react": { + "version": "6.5.16" + }, + "@storybook/testing-library": { + "version": "0.0.13" + }, + "@storybook/theming": { + "version": "6.5.16" + }, + "msw-storybook-addon": { + "version": "1.7.0" + }, + "storybook-mock-date-decorator": { + "version": "1.0.0" + } + }, + "framework": { + "name": "react" + }, + "addons": { + "@storybook/addon-links": { + "version": "6.5.16" + }, + "@storybook/addon-essentials": { + "version": "6.5.16" + }, + "@storybook/addon-interactions": { + "version": "6.5.16" + } + } +} diff --git a/node-src/lib/getPrebuiltStorybookMetadata.test.ts b/node-src/lib/getPrebuiltStorybookMetadata.test.ts index dfa1874c8..e14baf758 100644 --- a/node-src/lib/getPrebuiltStorybookMetadata.test.ts +++ b/node-src/lib/getPrebuiltStorybookMetadata.test.ts @@ -1,61 +1,93 @@ import { getStorybookMetadataFromProjectJson } from './getPrebuiltStorybookMetadata'; -import { readFile } from 'jsonfile'; -import { afterEach, describe, expect, it, vi } from 'vitest'; - -afterEach(() => { - vi.restoreAllMocks(); -}); - -vi.mock('jsonfile', async (importOriginal) => { - return { - // @ts-expect-error TS does not think actual is an object, but it's fine. - ...(await importOriginal()), - readFile: vi.fn(() => - Promise.resolve({ - addons: { - '@storybook/addon-essentials': { version: '8.1.0' }, - '@storybook/addon-links': { version: '8.1.0' }, - }, - builder: 'webpack5', - framework: { name: 'react' }, - storybookVersion: '8.1.0', - storybookPackages: { - '@storybook/react': { version: '8.1.0' }, - '@storybook/builder-webpack5': { version: '8.1.0' }, - '@storybook/addon-essentials': { version: '8.1.0' }, - '@storybook/addon-links': { version: '8.1.0' }, - }, - }) - ), - }; -}); +import { describe, expect, it } from 'vitest'; describe('getStorybookMetadataFromProjectJson', () => { it('should return the metadata from the project.json file', async () => { - const projectJsonPath = 'path/to/project.json'; + const projectJsonPath = 'bin-src/__mocks__/normalProjectJson/project.json'; + const metadata = await getStorybookMetadataFromProjectJson(projectJsonPath); + + expect(metadata).toEqual({ + viewLayer: '@storybook/react-webpack5', + version: '8.1.5', + builder: { + name: '@storybook/builder-webpack5', + packageVersion: '8.1.5', + }, + addons: [ + { + name: 'essentials', + packageName: '@storybook/addon-essentials', + packageVersion: '8.1.5', + }, + { + name: 'compiler-swc', + packageName: '@storybook/addon-webpack5-compiler-swc', + packageVersion: '1.0.2', + }, + ], + }); + }); + + it('should return the metadata from a Storybook 6 project.json file', async () => { + const projectJsonPath = 'bin-src/__mocks__/sb6ProjectJson/project.json'; const metadata = await getStorybookMetadataFromProjectJson(projectJsonPath); expect(metadata).toEqual({ viewLayer: 'react', - version: '8.1.0', + version: '6.5.16', builder: { - name: 'webpack5', - packageVersion: '8.1.0', + name: 'webpack4', + packageVersion: '6.5.16', }, addons: [ + { + name: 'links', + packageName: '@storybook/addon-links', + packageVersion: '6.5.16', + }, { name: 'essentials', packageName: '@storybook/addon-essentials', - packageVersion: '8.1.0', + packageVersion: '6.5.16', }, + { + name: 'interactions', + packageName: '@storybook/addon-interactions', + packageVersion: '6.5.16', + }, + ], + }); + }); + + it('should return the metadata from the project.json file when the builder is missing', async () => { + const projectJsonPath = 'bin-src/__mocks__/sb6ProjectJsonMissingBuilder/project.json'; + const metadata = await getStorybookMetadataFromProjectJson(projectJsonPath); + + expect(metadata).toEqual({ + viewLayer: 'react', + version: '6.5.16', + builder: { + name: 'webpack4', + packageVersion: '6.5.16', + }, + addons: [ { name: 'links', packageName: '@storybook/addon-links', - packageVersion: '8.1.0', + packageVersion: '6.5.16', + }, + { + name: 'essentials', + packageName: '@storybook/addon-essentials', + packageVersion: '6.5.16', + }, + { + name: 'interactions', + packageName: '@storybook/addon-interactions', + packageVersion: '6.5.16', }, ], }); - expect(readFile).toHaveBeenCalledWith(projectJsonPath); }); });