From d3099d0f541903749ce2279cb864b3119cb803e7 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Wed, 14 Apr 2021 13:35:57 +0200 Subject: [PATCH 1/6] Retrieve viewLayer and version from dependencies --- bin/lib/getStorybookInfo.js | 58 ++++++++++++++++++++++---- bin/lib/getStorybookInfo.test.js | 70 ++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 bin/lib/getStorybookInfo.test.js diff --git a/bin/lib/getStorybookInfo.js b/bin/lib/getStorybookInfo.js index dcf5b5be1..8ddbfac6c 100644 --- a/bin/lib/getStorybookInfo.js +++ b/bin/lib/getStorybookInfo.js @@ -1,6 +1,7 @@ // Figure out the Storybook version and view layer import fs from 'fs-extra'; +import semver from 'semver'; const viewLayers = [ 'react', @@ -66,29 +67,72 @@ const timeout = (count) => const neverResolve = new Promise(() => {}); const disregard = () => neverResolve; -const findViewlayer = async ({ env }) => { - // Allow setting Storybook version via CHROMATIC_STORYBOOK_VERSION='react@4.0-alpha.8' for unusual cases +const findViewlayer = async ({ env, log, options, packageJson }) => { + // Allow setting Storybook version via CHROMATIC_STORYBOOK_VERSION='@storybook/react@4.0-alpha.8' for unusual cases if (env.CHROMATIC_STORYBOOK_VERSION) { - const [viewLayer, version] = env.CHROMATIC_STORYBOOK_VERSION.split('@'); + const [viewLayer, v] = env.CHROMATIC_STORYBOOK_VERSION.replace('@storybook/', '').split('@'); + const version = semver.valid(v); if (!viewLayer || !version) { - throw new Error('CHROMATIC_STORYBOOK_VERSION was provided but could not be used'); + throw new Error( + 'Invalid CHROMATIC_STORYBOOK_VERSION; expecting something like "@storybook/react@6.2.0".' + ); + } + if (!viewLayers.includes(viewLayer)) { + throw new Error( + `Unsupported viewlayer specified in CHROMATIC_STORYBOOK_VERSION: ${viewLayer}` + ); } return { viewLayer, version }; } - // Try to find the Storybook viewlayer package + // Pull the viewlayer from dependencies in package.json + const dep = Object.entries(packageJson.dependencies || {}).find(([pkg]) => + viewLayers.some((viewLayer) => pkg === `@storybook/${viewLayer}`) + ); + const devDep = Object.entries(packageJson.devDependencies || {}).find(([pkg]) => + viewLayers.some((viewLayer) => pkg === `@storybook/${viewLayer}`) + ); + const peerDep = Object.entries(packageJson.peerDependencies || {}).find(([pkg]) => + viewLayers.some((viewLayer) => pkg === `@storybook/${viewLayer}`) + ); + const dependency = dep || devDep || peerDep; + + if (!dependency) { + throw new Error( + 'Could not find a supported Storybook viewlayer package in your package.json dependencies. Make sure one is installed.' + ); + } + if (dep && devDep && dep[0] === devDep[0]) { + log.warn( + `Found "${dep[0]}" in both "dependencies" and "devDependencies". This is probably a mistake.` + ); + } + if (dep && peerDep && dep[0] === peerDep[0]) { + log.warn( + `Found "${dep[0]}" in both "dependencies" and "peerDependencies". This is probably a mistake.` + ); + } + + const [pkg, version] = dependency; + const viewLayer = pkg.replace('@storybook/', ''); + + // If we won't need the Storybook CLI, we can exit early + // Note that `version` can be a semver range in this case. + if (options.storybookBuildDir) return { viewLayer, version }; + + // Try to find the viewlayer package in node_modules so we know it's installed const findings = viewLayers.map((v) => resolve(v)); const rejectedFindings = findings.map((p) => p.then(disregard, () => true)); const allFailed = Promise.all(rejectedFindings).then(() => { throw new Error( - 'Could not find a supported Storybook viewlayer package. Make sure one is installed, or set CHROMATIC_STORYBOOK_VERSION.' + 'Could not find a supported Storybook viewlayer package in node_modules. Make sure one is installed.' ); }); return Promise.race([ ...findings.map((p, i) => p.then( - (l) => read(l).then((r) => ({ viewLayer: viewLayers[i], ...r })), + (l) => read(l).then((r) => ({ viewLayer: viewLayers[i], version: r.version })), disregard // keep it pending forever ) ), diff --git a/bin/lib/getStorybookInfo.test.js b/bin/lib/getStorybookInfo.test.js new file mode 100644 index 000000000..f1e90d952 --- /dev/null +++ b/bin/lib/getStorybookInfo.test.js @@ -0,0 +1,70 @@ +import getStorybookInfo from './getStorybookInfo'; + +const log = { warn: jest.fn() }; +const context = { env: {}, log, options: {}, packageJson: {} }; + +const REACT = { '@storybook/react': '1.2.3' }; + +describe('getStorybookInfo', () => { + it('returns viewLayer and version', async () => { + const ctx = { ...context, packageJson: { dependencies: REACT } }; + await expect(getStorybookInfo(ctx)).resolves.toEqual( + // We're getting the result of tracing chromatic-cli's node_modules here. + expect.objectContaining({ viewLayer: 'react', version: expect.any(String) }) + ); + }); + + it('throws on missing dependency', async () => { + await expect(getStorybookInfo(context)).rejects.toThrow( + 'Could not find a supported Storybook viewlayer package in your package.json dependencies' + ); + }); + + it('warns on duplicate devDependency', async () => { + const ctx = { ...context, packageJson: { dependencies: REACT, devDependencies: REACT } }; + await getStorybookInfo(ctx); + expect(log.warn).toHaveBeenCalledWith( + expect.stringContaining('both "dependencies" and "devDependencies"') + ); + }); + + it('warns on duplicate peerDependency', async () => { + const ctx = { ...context, packageJson: { dependencies: REACT, peerDependencies: REACT } }; + await getStorybookInfo(ctx); + expect(log.warn).toHaveBeenCalledWith( + expect.stringContaining('both "dependencies" and "peerDependencies"') + ); + }); + + describe('with CHROMATIC_STORYBOOK_VERSION', () => { + it('returns viewLayer and version from env', async () => { + const ctx = { ...context, env: { CHROMATIC_STORYBOOK_VERSION: '@storybook/react@3.2.1' } }; + await expect(getStorybookInfo(ctx)).resolves.toEqual( + expect.objectContaining({ viewLayer: 'react', version: '3.2.1' }) + ); + }); + + it('throws on invalid value', async () => { + const ctx = { ...context, env: { CHROMATIC_STORYBOOK_VERSION: '3.2.1' } }; + await expect(getStorybookInfo(ctx)).rejects.toThrow('Invalid'); + }); + + it('throws on unsupported viewlayer', async () => { + const ctx = { ...context, env: { CHROMATIC_STORYBOOK_VERSION: '@storybook/native@3.2.1' } }; + await expect(getStorybookInfo(ctx)).rejects.toThrow('Unsupported'); + }); + }); + + describe('with --storybook-build-dir', () => { + it('returns viewLayer and version from packageJson', async () => { + const ctx = { + ...context, + options: { storybookBuildDir: 'storybook-static' }, + packageJson: { dependencies: REACT }, + }; + await expect(getStorybookInfo(ctx)).resolves.toEqual( + expect.objectContaining({ viewLayer: 'react', version: '1.2.3' }) + ); + }); + }); +}); From 585c5b104e09d5166af19311a4ae5acc72335b51 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Thu, 22 Apr 2021 12:46:13 +0200 Subject: [PATCH 2/6] Add support for @web/dev-server-storybook package --- bin/lib/getStorybookInfo.js | 143 ++++++++++++++----------------- bin/lib/getStorybookInfo.test.js | 7 ++ 2 files changed, 73 insertions(+), 77 deletions(-) diff --git a/bin/lib/getStorybookInfo.js b/bin/lib/getStorybookInfo.js index 8ddbfac6c..4028dcaee 100644 --- a/bin/lib/getStorybookInfo.js +++ b/bin/lib/getStorybookInfo.js @@ -3,62 +3,61 @@ import fs from 'fs-extra'; import semver from 'semver'; -const viewLayers = [ - 'react', - 'vue', - 'vue3', - 'angular', - 'html', - 'web-components', - 'polymer', - 'ember', - 'marko', - 'mithril', - 'riot', - 'svelte', - 'preact', - 'rax', -]; - -const supportedAddons = [ - 'a11y', - 'actions', - 'backgrounds', - 'centered', - 'contexts', - 'cssresources', - 'design-assets', - 'docs', - 'events', - 'google-analytics', - 'graphql', - 'info', - 'jest', - 'knobs', - 'links', - 'notes', - 'ondevice-actions', - 'ondevice-backgrounds', - 'ondevice-knobs', - 'ondevice-notes', - 'options', - 'queryparams', - 'storyshots', - 'storysource', - 'viewport', -]; - -const resolve = (name) => { +const viewLayers = { + '@storybook/react': 'react', + '@storybook/vue': 'vue', + '@storybook/vue3': 'vue3', + '@storybook/angular': 'angular', + '@storybook/html': 'html', + '@storybook/web-components': 'web-components', + '@storybook/polymer': 'polymer', + '@storybook/ember': 'ember', + '@storybook/marko': 'marko', + '@storybook/mithril': 'mithril', + '@storybook/riot': 'riot', + '@storybook/svelte': 'svelte', + '@storybook/preact': 'preact', + '@storybook/rax': 'rax', + '@web/dev-server-storybook': 'web-components', +}; + +const supportedAddons = { + '@storybook/addon-a11y': 'a11y', + '@storybook/addon-actions': 'actions', + '@storybook/addon-backgrounds': 'backgrounds', + '@storybook/addon-centered': 'centered', + '@storybook/addon-contexts': 'contexts', + '@storybook/addon-cssresources': 'cssresources', + '@storybook/addon-design-assets': 'design-assets', + '@storybook/addon-docs': 'docs', + '@storybook/addon-events': 'events', + '@storybook/addon-google-analytics': 'google-analytics', + '@storybook/addon-graphql': 'graphql', + '@storybook/addon-info': 'info', + '@storybook/addon-jest': 'jest', + '@storybook/addon-knobs': 'knobs', + '@storybook/addon-links': 'links', + '@storybook/addon-notes': 'notes', + '@storybook/addon-ondevice-actions': 'ondevice-actions', + '@storybook/addon-ondevice-backgrounds': 'ondevice-backgrounds', + '@storybook/addon-ondevice-knobs': 'ondevice-knobs', + '@storybook/addon-ondevice-notes': 'ondevice-notes', + '@storybook/addon-options': 'options', + '@storybook/addon-queryparams': 'queryparams', + '@storybook/addon-storyshots': 'storyshots', + '@storybook/addon-storysource': 'storysource', + '@storybook/addon-viewport': 'viewport', +}; + +const resolve = (pkg) => { try { - const path = require.resolve(`@storybook/${name}/package.json`, { paths: [process.cwd()] }); + const path = require.resolve(`${pkg}/package.json`, { paths: [process.cwd()] }); return Promise.resolve(path); } catch (error) { return Promise.reject(error); } }; -const read = async (filepath) => JSON.parse(await fs.readFile(filepath, 'utf8')); - const timeout = (count) => new Promise((_, rej) => { setTimeout(() => rej(new Error('The attempt to find the Storybook version timed out')), count); @@ -70,31 +69,24 @@ const disregard = () => neverResolve; const findViewlayer = async ({ env, log, options, packageJson }) => { // Allow setting Storybook version via CHROMATIC_STORYBOOK_VERSION='@storybook/react@4.0-alpha.8' for unusual cases if (env.CHROMATIC_STORYBOOK_VERSION) { - const [viewLayer, v] = env.CHROMATIC_STORYBOOK_VERSION.replace('@storybook/', '').split('@'); + const [, p, v] = env.CHROMATIC_STORYBOOK_VERSION.match(/(.+)@(.+)$/) || []; const version = semver.valid(v); - if (!viewLayer || !version) { + if (!p || !version) { throw new Error( 'Invalid CHROMATIC_STORYBOOK_VERSION; expecting something like "@storybook/react@6.2.0".' ); } - if (!viewLayers.includes(viewLayer)) { - throw new Error( - `Unsupported viewlayer specified in CHROMATIC_STORYBOOK_VERSION: ${viewLayer}` - ); + const viewLayer = viewLayers[p] || viewLayers[`@storybook/${p}`]; + if (!viewLayer) { + throw new Error(`Unsupported viewlayer specified in CHROMATIC_STORYBOOK_VERSION: ${p}`); } return { viewLayer, version }; } // Pull the viewlayer from dependencies in package.json - const dep = Object.entries(packageJson.dependencies || {}).find(([pkg]) => - viewLayers.some((viewLayer) => pkg === `@storybook/${viewLayer}`) - ); - const devDep = Object.entries(packageJson.devDependencies || {}).find(([pkg]) => - viewLayers.some((viewLayer) => pkg === `@storybook/${viewLayer}`) - ); - const peerDep = Object.entries(packageJson.peerDependencies || {}).find(([pkg]) => - viewLayers.some((viewLayer) => pkg === `@storybook/${viewLayer}`) - ); + const dep = Object.entries(packageJson.dependencies || {}).find(([p]) => viewLayers[p]); + const devDep = Object.entries(packageJson.devDependencies || {}).find(([p]) => viewLayers[p]); + const peerDep = Object.entries(packageJson.peerDependencies || {}).find(([p]) => viewLayers[p]); const dependency = dep || devDep || peerDep; if (!dependency) { @@ -121,8 +113,8 @@ const findViewlayer = async ({ env, log, options, packageJson }) => { if (options.storybookBuildDir) return { viewLayer, version }; // Try to find the viewlayer package in node_modules so we know it's installed - const findings = viewLayers.map((v) => resolve(v)); - const rejectedFindings = findings.map((p) => p.then(disregard, () => true)); + const findings = Object.entries(viewLayers).map(([pk, name]) => [resolve(pk), name]); + const rejectedFindings = findings.map(([p]) => p.then(disregard, () => true)); const allFailed = Promise.all(rejectedFindings).then(() => { throw new Error( 'Could not find a supported Storybook viewlayer package in node_modules. Make sure one is installed.' @@ -130,11 +122,10 @@ const findViewlayer = async ({ env, log, options, packageJson }) => { }); return Promise.race([ - ...findings.map((p, i) => - p.then( - (l) => read(l).then((r) => ({ viewLayer: viewLayers[i], version: r.version })), - disregard // keep it pending forever - ) + ...findings.map(([promise, name]) => + promise + .then(fs.readJson, disregard) + .then((pkgJson) => ({ viewLayer: name, version: pkgJson.version })) ), allFailed, timeout(10000), @@ -143,12 +134,10 @@ const findViewlayer = async ({ env, log, options, packageJson }) => { const findAddons = async () => { const result = await Promise.all( - supportedAddons.map((name) => - resolve(`addon-${name}`) - .then((l) => - read(l).then((r) => ({ name, packageName: r.name, packageVersion: r.version })) - ) - .catch((e) => false) + Object.entries(supportedAddons).map(([pkg, name]) => + resolve(pkg) + .then(fs.readJson, () => false) + .then((pkgJson) => ({ name, packageName: pkgJson.name, packageVersion: pkgJson.version })) ) ); diff --git a/bin/lib/getStorybookInfo.test.js b/bin/lib/getStorybookInfo.test.js index f1e90d952..dcc4d6cd1 100644 --- a/bin/lib/getStorybookInfo.test.js +++ b/bin/lib/getStorybookInfo.test.js @@ -44,6 +44,13 @@ describe('getStorybookInfo', () => { ); }); + it('supports unscoped package name', async () => { + const ctx = { ...context, env: { CHROMATIC_STORYBOOK_VERSION: 'react@3.2.1' } }; + await expect(getStorybookInfo(ctx)).resolves.toEqual( + expect.objectContaining({ viewLayer: 'react', version: '3.2.1' }) + ); + }); + it('throws on invalid value', async () => { const ctx = { ...context, env: { CHROMATIC_STORYBOOK_VERSION: '3.2.1' } }; await expect(getStorybookInfo(ctx)).rejects.toThrow('Invalid'); From 5accc297a2ce9c8b3fb66c9194ab441d4f7694c7 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Thu, 22 Apr 2021 12:51:31 +0200 Subject: [PATCH 3/6] Clarify what semver.valid is for --- bin/lib/getStorybookInfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/lib/getStorybookInfo.js b/bin/lib/getStorybookInfo.js index 4028dcaee..ad1c103f6 100644 --- a/bin/lib/getStorybookInfo.js +++ b/bin/lib/getStorybookInfo.js @@ -70,7 +70,7 @@ const findViewlayer = async ({ env, log, options, packageJson }) => { // Allow setting Storybook version via CHROMATIC_STORYBOOK_VERSION='@storybook/react@4.0-alpha.8' for unusual cases if (env.CHROMATIC_STORYBOOK_VERSION) { const [, p, v] = env.CHROMATIC_STORYBOOK_VERSION.match(/(.+)@(.+)$/) || []; - const version = semver.valid(v); + const version = semver.valid(v); // ensures we get a specific version, not a range if (!p || !version) { throw new Error( 'Invalid CHROMATIC_STORYBOOK_VERSION; expecting something like "@storybook/react@6.2.0".' From 0ac101706acc0f8312f309e73f866b486b5327bb Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Fri, 23 Apr 2021 11:02:06 +0200 Subject: [PATCH 4/6] Nicer error messages for missing viewLayer --- bin/lib/getStorybookInfo.js | 11 +++++------ bin/ui/messages/errors/noViewLayerDependency.js | 13 +++++++++++++ .../errors/noViewLayerDependency.stories.js | 7 +++++++ bin/ui/messages/errors/noViewLayerPackage.js | 11 +++++++++++ .../messages/errors/noViewLayerPackage.stories.js | 7 +++++++ 5 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 bin/ui/messages/errors/noViewLayerDependency.js create mode 100644 bin/ui/messages/errors/noViewLayerDependency.stories.js create mode 100644 bin/ui/messages/errors/noViewLayerPackage.js create mode 100644 bin/ui/messages/errors/noViewLayerPackage.stories.js diff --git a/bin/lib/getStorybookInfo.js b/bin/lib/getStorybookInfo.js index ad1c103f6..8881d2d37 100644 --- a/bin/lib/getStorybookInfo.js +++ b/bin/lib/getStorybookInfo.js @@ -3,6 +3,9 @@ import fs from 'fs-extra'; import semver from 'semver'; +import noViewLayerDependency from '../ui/messages/errors/noViewLayerDependency'; +import noViewLayerPackage from '../ui/messages/errors/noViewLayerPackage'; + const viewLayers = { '@storybook/react': 'react', '@storybook/vue': 'vue', @@ -90,9 +93,7 @@ const findViewlayer = async ({ env, log, options, packageJson }) => { const dependency = dep || devDep || peerDep; if (!dependency) { - throw new Error( - 'Could not find a supported Storybook viewlayer package in your package.json dependencies. Make sure one is installed.' - ); + throw new Error(noViewLayerDependency()); } if (dep && devDep && dep[0] === devDep[0]) { log.warn( @@ -116,9 +117,7 @@ const findViewlayer = async ({ env, log, options, packageJson }) => { const findings = Object.entries(viewLayers).map(([pk, name]) => [resolve(pk), name]); const rejectedFindings = findings.map(([p]) => p.then(disregard, () => true)); const allFailed = Promise.all(rejectedFindings).then(() => { - throw new Error( - 'Could not find a supported Storybook viewlayer package in node_modules. Make sure one is installed.' - ); + throw new Error(noViewLayerPackage()); }); return Promise.race([ diff --git a/bin/ui/messages/errors/noViewLayerDependency.js b/bin/ui/messages/errors/noViewLayerDependency.js new file mode 100644 index 000000000..0716673a6 --- /dev/null +++ b/bin/ui/messages/errors/noViewLayerDependency.js @@ -0,0 +1,13 @@ +import chalk from 'chalk'; +import dedent from 'ts-dedent'; + +import { error, info } from '../../components/icons'; +import link from '../../components/link'; + +export default () => + dedent(chalk` + ${error} {bold Storybook dependency not found} + Could not find a supported Storybook viewlayer dependency in your {bold package.json}. + Make sure you have setup Storybook and are running Chromatic from the same directory. + ${info} New to Storybook? Read ${link('https://www.chromatic.com/docs/storybook')} + `); diff --git a/bin/ui/messages/errors/noViewLayerDependency.stories.js b/bin/ui/messages/errors/noViewLayerDependency.stories.js new file mode 100644 index 000000000..6e331ce45 --- /dev/null +++ b/bin/ui/messages/errors/noViewLayerDependency.stories.js @@ -0,0 +1,7 @@ +import noViewLayerDependency from './noViewLayerDependency'; + +export default { + title: 'CLI/Messages/Errors', +}; + +export const NoViewLayerDependency = () => noViewLayerDependency(); diff --git a/bin/ui/messages/errors/noViewLayerPackage.js b/bin/ui/messages/errors/noViewLayerPackage.js new file mode 100644 index 000000000..191828f3f --- /dev/null +++ b/bin/ui/messages/errors/noViewLayerPackage.js @@ -0,0 +1,11 @@ +import chalk from 'chalk'; +import dedent from 'ts-dedent'; + +import { error } from '../../components/icons'; + +export default () => + dedent(chalk` + ${error} {bold Storybook package not found} + Could not find a supported Storybook viewlayer package in {bold node_modules}. + Most likely you forgot to run {bold npm install} or {bold yarn} before running Chromatic. + `); diff --git a/bin/ui/messages/errors/noViewLayerPackage.stories.js b/bin/ui/messages/errors/noViewLayerPackage.stories.js new file mode 100644 index 000000000..7188d156a --- /dev/null +++ b/bin/ui/messages/errors/noViewLayerPackage.stories.js @@ -0,0 +1,7 @@ +import noViewLayerPackage from './noViewLayerPackage'; + +export default { + title: 'CLI/Messages/Errors', +}; + +export const NoViewLayerPackage = () => noViewLayerPackage(); From 4f994b17d860edb30442826314ee74346bc5d276 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Fri, 23 Apr 2021 11:21:42 +0200 Subject: [PATCH 5/6] Check that the viewLayer specified in package.json is installed, not another one --- bin/lib/getStorybookInfo.js | 19 ++++--------------- bin/lib/getStorybookInfo.test.js | 10 +++++++--- bin/ui/messages/errors/noViewLayerPackage.js | 6 +++--- .../errors/noViewLayerPackage.stories.js | 2 +- 4 files changed, 15 insertions(+), 22 deletions(-) diff --git a/bin/lib/getStorybookInfo.js b/bin/lib/getStorybookInfo.js index 8881d2d37..9e72c82a3 100644 --- a/bin/lib/getStorybookInfo.js +++ b/bin/lib/getStorybookInfo.js @@ -66,9 +66,6 @@ const timeout = (count) => setTimeout(() => rej(new Error('The attempt to find the Storybook version timed out')), count); }); -const neverResolve = new Promise(() => {}); -const disregard = () => neverResolve; - const findViewlayer = async ({ env, log, options, packageJson }) => { // Allow setting Storybook version via CHROMATIC_STORYBOOK_VERSION='@storybook/react@4.0-alpha.8' for unusual cases if (env.CHROMATIC_STORYBOOK_VERSION) { @@ -114,19 +111,11 @@ const findViewlayer = async ({ env, log, options, packageJson }) => { if (options.storybookBuildDir) return { viewLayer, version }; // Try to find the viewlayer package in node_modules so we know it's installed - const findings = Object.entries(viewLayers).map(([pk, name]) => [resolve(pk), name]); - const rejectedFindings = findings.map(([p]) => p.then(disregard, () => true)); - const allFailed = Promise.all(rejectedFindings).then(() => { - throw new Error(noViewLayerPackage()); - }); - return Promise.race([ - ...findings.map(([promise, name]) => - promise - .then(fs.readJson, disregard) - .then((pkgJson) => ({ viewLayer: name, version: pkgJson.version })) - ), - allFailed, + resolve(pkg) + .then(fs.readJson) + .then((json) => ({ viewLayer, version: json.version })) + .catch(() => Promise.reject(new Error(noViewLayerPackage(pkg)))), timeout(10000), ]); }; diff --git a/bin/lib/getStorybookInfo.test.js b/bin/lib/getStorybookInfo.test.js index dcc4d6cd1..36dbd9b1c 100644 --- a/bin/lib/getStorybookInfo.test.js +++ b/bin/lib/getStorybookInfo.test.js @@ -4,6 +4,7 @@ const log = { warn: jest.fn() }; const context = { env: {}, log, options: {}, packageJson: {} }; const REACT = { '@storybook/react': '1.2.3' }; +const VUE = { '@storybook/vue': '1.2.3' }; describe('getStorybookInfo', () => { it('returns viewLayer and version', async () => { @@ -15,9 +16,7 @@ describe('getStorybookInfo', () => { }); it('throws on missing dependency', async () => { - await expect(getStorybookInfo(context)).rejects.toThrow( - 'Could not find a supported Storybook viewlayer package in your package.json dependencies' - ); + await expect(getStorybookInfo(context)).rejects.toThrow('Storybook dependency not found'); }); it('warns on duplicate devDependency', async () => { @@ -36,6 +35,11 @@ describe('getStorybookInfo', () => { ); }); + it('throws on missing package', async () => { + const ctx = { ...context, packageJson: { dependencies: VUE } }; + await expect(getStorybookInfo(ctx)).rejects.toThrow('Storybook package not installed'); + }); + describe('with CHROMATIC_STORYBOOK_VERSION', () => { it('returns viewLayer and version from env', async () => { const ctx = { ...context, env: { CHROMATIC_STORYBOOK_VERSION: '@storybook/react@3.2.1' } }; diff --git a/bin/ui/messages/errors/noViewLayerPackage.js b/bin/ui/messages/errors/noViewLayerPackage.js index 191828f3f..97632bfee 100644 --- a/bin/ui/messages/errors/noViewLayerPackage.js +++ b/bin/ui/messages/errors/noViewLayerPackage.js @@ -3,9 +3,9 @@ import dedent from 'ts-dedent'; import { error } from '../../components/icons'; -export default () => +export default (pkg) => dedent(chalk` - ${error} {bold Storybook package not found} - Could not find a supported Storybook viewlayer package in {bold node_modules}. + ${error} {bold Storybook package not installed} + Could not find {bold ${pkg}} in {bold node_modules}. Most likely you forgot to run {bold npm install} or {bold yarn} before running Chromatic. `); diff --git a/bin/ui/messages/errors/noViewLayerPackage.stories.js b/bin/ui/messages/errors/noViewLayerPackage.stories.js index 7188d156a..fa04c2f0e 100644 --- a/bin/ui/messages/errors/noViewLayerPackage.stories.js +++ b/bin/ui/messages/errors/noViewLayerPackage.stories.js @@ -4,4 +4,4 @@ export default { title: 'CLI/Messages/Errors', }; -export const NoViewLayerPackage = () => noViewLayerPackage(); +export const NoViewLayerPackage = () => noViewLayerPackage('@storybook/vue'); From 289b9b5b0811f1107a16d2f06da218fa4e9de6b9 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Fri, 23 Apr 2021 15:20:27 +0200 Subject: [PATCH 6/6] Update bin/ui/messages/errors/noViewLayerPackage.js Co-authored-by: Dominic Nguyen --- bin/ui/messages/errors/noViewLayerPackage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/ui/messages/errors/noViewLayerPackage.js b/bin/ui/messages/errors/noViewLayerPackage.js index 97632bfee..9821bcff4 100644 --- a/bin/ui/messages/errors/noViewLayerPackage.js +++ b/bin/ui/messages/errors/noViewLayerPackage.js @@ -7,5 +7,5 @@ export default (pkg) => dedent(chalk` ${error} {bold Storybook package not installed} Could not find {bold ${pkg}} in {bold node_modules}. - Most likely you forgot to run {bold npm install} or {bold yarn} before running Chromatic. + Most likely, you forgot to run {bold npm install} or {bold yarn} before running Chromatic. `);