-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vitest: Implement add command for vitest addon #28920
Changes from 1 commit
46a838f
3cee65e
1a4a5e7
f4db6c0
c98d4c2
480f404
e9070eb
675fdb8
dbd4844
419b81c
71ad827
718b879
a26e267
ce006bf
76734a0
78d544e
b45a9b4
d8a5c72
cc42862
3d68903
b80775b
ce2afff
4d80b1f
0a35a32
f1031cb
61338bf
cd8f1f2
c17df9f
9630148
dc9432a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,169 @@ | ||
export default async function postinstall(context: any) { | ||
console.log('[addon-vitest] postinstall with', context); | ||
import { existsSync } from 'node:fs'; | ||
import * as fs from 'node:fs/promises'; | ||
import { writeFile } from 'node:fs/promises'; | ||
import { join, resolve } from 'node:path'; | ||
|
||
import { | ||
JsPackageManagerFactory, | ||
extractProperFrameworkName, | ||
loadAllPresets, | ||
loadMainConfig, | ||
} from 'storybook/internal/common'; | ||
import { logger } from 'storybook/internal/node-logger'; | ||
|
||
import c from 'tinyrainbow'; | ||
import dedent from 'ts-dedent'; | ||
|
||
import { type PostinstallOptions } from '../../../lib/cli-storybook/src/add'; | ||
|
||
export default async function postInstall(options: PostinstallOptions) { | ||
const packageManager = JsPackageManagerFactory.getPackageManager({ | ||
force: options.packageManager, | ||
}); | ||
|
||
const info = await getFrameworkInfo(options); | ||
|
||
kasperpeulen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (info.builderPackageName !== '@storybook/builder-vite') { | ||
logger.info('Only @storybook/builder-vite is supported'); | ||
return; | ||
} | ||
|
||
const configFile = resolve('vitest.config.ts'); | ||
if (existsSync(configFile)) { | ||
logger.info('You already have a vitest.config.ts file. Check our docs:'); | ||
return; | ||
} | ||
|
||
const annotationsImport = [ | ||
'@storybook/nextjs', | ||
'@storybook/experimental-nextjs-vite', | ||
'@storybook/sveltekit', | ||
].includes(info.frameworkPackageName) | ||
? info.frameworkPackageName | ||
: ['@storybook/react', '@storybook/svelte', '@storybook/vue3'].includes( | ||
info.rendererPackageName | ||
kasperpeulen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
? info.rendererPackageName | ||
: null; | ||
|
||
if (!annotationsImport) { | ||
logger.info('Your framework is not yet supported for the vitest addon.'); | ||
return; | ||
} | ||
|
||
const vitestInfo = getVitestPluginInfo(info.frameworkPackageName); | ||
|
||
const packages = ['vitest@latest', '@vitest/browser@latest', 'playwright@latest']; | ||
logger.info(c.bold('Installing packages...')); | ||
yannbf marked this conversation as resolved.
Show resolved
Hide resolved
yannbf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
logger.info(packages.join(', ')); | ||
await packageManager.addDependencies({ installAsDevDependencies: true }, packages); | ||
|
||
kasperpeulen marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if this or any of the other operations fail? Should we wrap in a try/catch to provide some narrative about the failure? Perhaps we may want to add telemetry to track these? |
||
await packageManager.executeCommand({ | ||
command: 'npx', | ||
args: ['playwright', 'install', 'chromium', '--with-deps'], | ||
}); | ||
|
||
await writeFile( | ||
resolve(options.configDir, 'vitest.setup.ts'), | ||
dedent` | ||
kasperpeulen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import { beforeAll } from 'vitest' | ||
import { setProjectAnnotations } from '${annotationsImport}' | ||
import * as projectAnnotations from './preview' | ||
|
||
kasperpeulen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const project = setProjectAnnotations(projectAnnotations) | ||
|
||
beforeAll(project.beforeAll) | ||
` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make sure the snippet matches what we have in the docs for portable stories, or change the docs for portable stories to match the snippet There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what you mean? import { beforeAll } from 'vitest';
import { render as testingLibraryRender } from '@testing-library/svelte';
import { setProjectAnnotations } from '@storybook/svelte';
// 👇 Import the exported annotations, if any, from the addons you're using; otherwise remove this
import * as addonAnnotations from 'my-addon/preview';
import * as previewAnnotations from './.storybook/preview';
const annotations = setProjectAnnotations([
previewAnnotations,
addonAnnotations,
// You MUST provide this option to use portable stories with vitest
{ testingLibraryRender },
]);
// Run Storybook's beforeAll hook
beforeAll(annotations.beforeAll); I can remove the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kylegach Let's discuss this for another PR |
||
); | ||
await writeFile( | ||
configFile, | ||
dedent` | ||
import { defineConfig } from "vitest/config"; | ||
import { storybookTest } from "@storybook/experimental-addon-vitest/plugin"; | ||
${vitestInfo.frameworkPluginImport ? vitestInfo.frameworkPluginImport + '\n' : ''} | ||
export default defineConfig({ | ||
plugins: [ | ||
storybookTest(),${vitestInfo.frameworkPluginCall ? '\n' + vitestInfo.frameworkPluginCall : ''} | ||
], | ||
test: { | ||
include: ['**/*.{stories}.?(m)[jt]s?(x)'], | ||
browser: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: The glob pattern for stories files might be too permissive |
||
enabled: true, | ||
name: 'chromium', | ||
provider: 'playwright', | ||
headless: true, | ||
screenshotFailures: false, | ||
}, | ||
isolate: false, | ||
setupFiles: ['./.storybook/vitest.setup.ts'], | ||
}, | ||
}) | ||
` | ||
); | ||
} | ||
|
||
const getVitestPluginInfo = (framework: string) => { | ||
let frameworkPluginImport = ''; | ||
let frameworkPluginCall = ''; | ||
|
||
if (framework === '@storybook/nextjs') { | ||
frameworkPluginImport = "import vitePluginNext from 'vite-plugin-storybook-nextjs'"; | ||
frameworkPluginCall = 'vitePluginNext()'; | ||
} | ||
|
||
if (framework === '@storybook/sveltekit') { | ||
frameworkPluginImport = "import { storybookSveltekitPlugin } from '@storybook/sveltekit/vite'"; | ||
frameworkPluginCall = 'storybookSveltekitPlugin()'; | ||
} | ||
|
||
return { frameworkPluginImport, frameworkPluginCall }; | ||
}; | ||
|
||
async function getFrameworkInfo({ configDir, packageManager: pkgMgr }: PostinstallOptions) { | ||
const packageManager = JsPackageManagerFactory.getPackageManager({ force: pkgMgr }); | ||
const packageJson = await packageManager.retrievePackageJson(); | ||
|
||
const config = await loadMainConfig({ configDir, noCache: true }); | ||
const { framework } = config; | ||
|
||
const frameworkName = typeof framework === 'string' ? framework : framework?.name; | ||
|
||
if (!frameworkName) { | ||
throw new Error('Could not detect your storybook framework.'); | ||
} | ||
kasperpeulen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const frameworkPackageName = extractProperFrameworkName(frameworkName); | ||
|
||
const presets = await loadAllPresets({ | ||
corePresets: [join(frameworkName, 'preset')], | ||
overridePresets: [ | ||
require.resolve('@storybook/core/core-server/presets/common-override-preset'), | ||
], | ||
kasperpeulen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
configDir, | ||
packageJson, | ||
isCritical: true, | ||
}); | ||
|
||
const core = await presets.apply('core', {}); | ||
|
||
const { builder, renderer } = core; | ||
|
||
if (!builder || !renderer) { | ||
throw new Error('Could not detect your storybook framework.'); | ||
} | ||
kasperpeulen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const builderPackageJson = await fs.readFile( | ||
`${typeof builder === 'string' ? builder : builder.name}/package.json`, | ||
'utf8' | ||
); | ||
const builderPackageName = JSON.parse(builderPackageJson).name; | ||
Comment on lines
+237
to
+240
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Wrap this in a try/catch to handle potential file read errors
Comment on lines
+237
to
+240
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Wrap this in a try/catch to handle potential file read errors |
||
|
||
const rendererPackageJson = await fs.readFile(`${renderer}/package.json`, 'utf8'); | ||
const rendererPackageName = JSON.parse(rendererPackageJson).name; | ||
|
||
return { | ||
frameworkPackageName, | ||
builderPackageName, | ||
rendererPackageName, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to do any version checks here? Given that these packages will only fully work in Storybook 8.3? Specially sveltekit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this
postinstall
will only be available in 8.3 right?