From 87b623baefa75bacc6b6e5b51fe02ce7cf0d6955 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Fri, 25 Oct 2024 16:55:54 +0200 Subject: [PATCH 01/11] Track test provider state in sessionStorage --- .../components/sidebar/SidebarBottom.tsx | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/code/core/src/manager/components/sidebar/SidebarBottom.tsx b/code/core/src/manager/components/sidebar/SidebarBottom.tsx index 48bf60a5f095..851731270b98 100644 --- a/code/core/src/manager/components/sidebar/SidebarBottom.tsx +++ b/code/core/src/manager/components/sidebar/SidebarBottom.tsx @@ -30,6 +30,8 @@ const SIDEBAR_BOTTOM_SPACER_ID = 'sidebar-bottom-spacer'; // This ID is used by some integrators to target the (fixed position) sidebar bottom element so it should remain stable. const SIDEBAR_BOTTOM_WRAPPER_ID = 'sidebar-bottom-wrapper'; +const STORAGE_KEY = '@storybook/manager/test-providers'; + const initialTestProviderState: TestProviderState = { details: {} as { [key: string]: any }, cancellable: false, @@ -97,13 +99,17 @@ export const SidebarBottomBase = ({ api, notifications = [], status = {} }: Side const wrapperRef = useRef(null); const [warningsActive, setWarningsActive] = useState(false); const [errorsActive, setErrorsActive] = useState(false); - const [testProviders, setTestProviders] = useState(() => - Object.fromEntries( + const [testProviders, setTestProviders] = useState(() => { + let sessionState: TestProviders = {}; + try { + sessionState = JSON.parse(sessionStorage.getItem(STORAGE_KEY) || '{}'); + } catch (_) {} + return Object.fromEntries( Object.entries(api.getElements(Addon_TypesEnum.experimental_TEST_PROVIDER)).map( - ([id, config]) => [id, { ...config, ...initialTestProviderState }] + ([id, config]) => [id, { ...config, ...initialTestProviderState, ...sessionState[id] }] ) - ) - ); + ); + }); const warnings = Object.values(status).filter((statusByAddonId) => Object.values(statusByAddonId).some((value) => value?.status === 'warn') @@ -116,7 +122,11 @@ export const SidebarBottomBase = ({ api, notifications = [], status = {} }: Side const updateTestProvider = useCallback( (id: TestProviderId, update: Partial) => - setTestProviders((state) => ({ ...state, [id]: { ...state[id], ...update } })), + setTestProviders((state) => { + const newValue = { ...state, [id]: { ...state[id], ...update } }; + sessionStorage.setItem(STORAGE_KEY, JSON.stringify(newValue)); + return newValue; + }), [] ); @@ -130,6 +140,7 @@ export const SidebarBottomBase = ({ api, notifications = [], status = {} }: Side progress: undefined, }; setTestProviders((state) => ({ ...state, [id]: { ...state[id], ...startingState } })); + sessionStorage.removeItem(STORAGE_KEY); api.experimental_updateStatus(id, (state = {}) => Object.fromEntries(Object.keys(state).map((key) => [key, null])) ); From 13c9a2027498a15a721ddc44b7f536b6ae3a625a Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 28 Oct 2024 12:33:39 +0100 Subject: [PATCH 02/11] Refactor NPMProxy error parsing logic This commit refactors the error parsing logic in the NPMProxy class. It updates the regular expression used to match npm errors and extracts the error code from the error message. This change improves the accuracy of error handling in the NPMProxy class. --- .../common/js-package-manager/NPMProxy.test.ts | 16 +++++++++++++++- .../src/common/js-package-manager/NPMProxy.ts | 4 ++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/code/core/src/common/js-package-manager/NPMProxy.test.ts b/code/core/src/common/js-package-manager/NPMProxy.test.ts index 4a783017d917..11f34a986bf1 100644 --- a/code/core/src/common/js-package-manager/NPMProxy.test.ts +++ b/code/core/src/common/js-package-manager/NPMProxy.test.ts @@ -428,7 +428,7 @@ describe('NPM Proxy', () => { describe('parseErrors', () => { it('should parse npm errors', () => { - const NPM_RESOLVE_ERROR_SAMPLE = ` + const NPM_LEGACY_RESOLVE_ERROR_SAMPLE = ` npm ERR! npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree @@ -439,6 +439,17 @@ describe('NPM Proxy', () => { npm ERR! react@"30" from the root project `; + const NPM_RESOLVE_ERROR_SAMPLE = ` + npm error + npm error code ERESOLVE + npm error ERESOLVE unable to resolve dependency tree + npm error + npm error While resolving: before-storybook@1.0.0 + npm error Found: react@undefined + npm error node_modules/react + npm error react@"30" from the root project + `; + const NPM_TIMEOUT_ERROR_SAMPLE = ` npm notice npm notice New major version of npm available! 8.5.0 -> 9.6.7 @@ -451,6 +462,9 @@ describe('NPM Proxy', () => { npm ERR! network This is a problem related to network connectivity. `; + expect(npmProxy.parseErrorFromLogs(NPM_LEGACY_RESOLVE_ERROR_SAMPLE)).toEqual( + 'NPM error ERESOLVE - Dependency resolution error.' + ); expect(npmProxy.parseErrorFromLogs(NPM_RESOLVE_ERROR_SAMPLE)).toEqual( 'NPM error ERESOLVE - Dependency resolution error.' ); diff --git a/code/core/src/common/js-package-manager/NPMProxy.ts b/code/core/src/common/js-package-manager/NPMProxy.ts index 90378de122cf..ea673f9df301 100644 --- a/code/core/src/common/js-package-manager/NPMProxy.ts +++ b/code/core/src/common/js-package-manager/NPMProxy.ts @@ -28,8 +28,8 @@ type NpmDependencies = { export type NpmListOutput = { dependencies: NpmDependencies; }; +const NPM_ERROR_REGEX = /npm (ERR!|error) (code|errno) (\w+)/i; -const NPM_ERROR_REGEX = /npm ERR! code (\w+)/; const NPM_ERROR_CODES = { E401: 'Authentication failed or is required.', E403: 'Access to the resource is forbidden.', @@ -320,7 +320,7 @@ export class NPMProxy extends JsPackageManager { const match = logs.match(NPM_ERROR_REGEX); if (match) { - const errorCode = match[1] as keyof typeof NPM_ERROR_CODES; + const errorCode = match[3] as keyof typeof NPM_ERROR_CODES; if (errorCode) { finalMessage = `${finalMessage} ${errorCode}`; } From 15dcb362f0fb6e9c6dcbe4e425c729b3d4dfbde2 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Mon, 28 Oct 2024 14:22:57 +0100 Subject: [PATCH 03/11] Prevent clearing sessionStorage for other test providers when clearing state for one --- .../src/manager/components/sidebar/SidebarBottom.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/code/core/src/manager/components/sidebar/SidebarBottom.tsx b/code/core/src/manager/components/sidebar/SidebarBottom.tsx index 851731270b98..4bd087e681ca 100644 --- a/code/core/src/manager/components/sidebar/SidebarBottom.tsx +++ b/code/core/src/manager/components/sidebar/SidebarBottom.tsx @@ -131,21 +131,19 @@ export const SidebarBottomBase = ({ api, notifications = [], status = {} }: Side ); const clearState = useCallback( - ({ providerId: id }: { providerId: TestProviderId }) => { - const startingState: Partial = { + ({ providerId }: { providerId: TestProviderId }) => { + updateTestProvider(providerId, { cancelling: false, running: true, failed: false, crashed: false, progress: undefined, - }; - setTestProviders((state) => ({ ...state, [id]: { ...state[id], ...startingState } })); - sessionStorage.removeItem(STORAGE_KEY); - api.experimental_updateStatus(id, (state = {}) => + }); + api.experimental_updateStatus(providerId, (state = {}) => Object.fromEntries(Object.keys(state).map((key) => [key, null])) ); }, - [api] + [api, updateTestProvider] ); const onRunTests = useCallback( From 913300fb7944a3f7bc899df7e0cfc60e4c7a26a7 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Mon, 28 Oct 2024 14:25:40 +0100 Subject: [PATCH 04/11] Upgrade VTA to v3.2.0 to resolve peerDep conflict --- code/package.json | 2 +- code/yarn.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/package.json b/code/package.json index d45bb18f3f43..257aaa624cb1 100644 --- a/code/package.json +++ b/code/package.json @@ -90,7 +90,7 @@ "type-fest": "~2.19" }, "dependencies": { - "@chromatic-com/storybook": "^3.1.0", + "@chromatic-com/storybook": "^3.2.0", "@happy-dom/global-registrator": "^14.12.0", "@nx/eslint": "18.0.6", "@nx/vite": "18.0.6", diff --git a/code/yarn.lock b/code/yarn.lock index 3dd05cb81d27..e0e8691f14e3 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -2354,9 +2354,9 @@ __metadata: languageName: node linkType: hard -"@chromatic-com/storybook@npm:^3.1.0": - version: 3.1.0 - resolution: "@chromatic-com/storybook@npm:3.1.0" +"@chromatic-com/storybook@npm:^3.2.0": + version: 3.2.0 + resolution: "@chromatic-com/storybook@npm:3.2.0" dependencies: "@storybook/channels": "npm:^8.3.0" "@storybook/telemetry": "npm:^8.3.0" @@ -2367,8 +2367,8 @@ __metadata: react-confetti: "npm:^6.1.0" strip-ansi: "npm:^7.1.0" peerDependencies: - storybook: ^8.3.0 - checksum: 10c0/cb9672d828f076e9a6c7277fe08a846d05316fb7d3e625862fc667718f5abc2746ff7cea04507e5cbc0136a4d55950fce88ea91420e8d3c05d84f528050a1dce + storybook: "*" + checksum: 10c0/59485e69a55df6b1998e19bf0e129fa1f9a86d3ae541f4dcb6f6dd945e7b9a6258ce75e244aaa73821039cef8c57424402a3c0bf63a66b4511a2ac0b5611103b languageName: node linkType: hard @@ -6833,7 +6833,7 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/root@workspace:." dependencies: - "@chromatic-com/storybook": "npm:^3.1.0" + "@chromatic-com/storybook": "npm:^3.2.0" "@happy-dom/global-registrator": "npm:^14.12.0" "@nx/eslint": "npm:18.0.6" "@nx/vite": "npm:18.0.6" From 71e6ec7463665d2b0e4ed55b1e1595115ff258bb Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Tue, 29 Oct 2024 15:46:38 +0100 Subject: [PATCH 05/11] Addon Test: Improve Error Handling --- code/addons/test/src/manager.tsx | 9 +- code/addons/test/src/node/boot-test-runner.ts | 6 +- code/addons/test/src/node/reporter.ts | 84 ++++++++++--------- code/addons/test/src/preset.ts | 1 - .../src/core-events/data/testing-module.ts | 2 + .../components/sidebar/SidebarBottom.tsx | 8 +- code/core/src/types/modules/addons.ts | 8 +- 7 files changed, 65 insertions(+), 53 deletions(-) diff --git a/code/addons/test/src/manager.tsx b/code/addons/test/src/manager.tsx index 37be0f132bce..12a2c0ab84f9 100644 --- a/code/addons/test/src/manager.tsx +++ b/code/addons/test/src/manager.tsx @@ -94,10 +94,10 @@ addons.register(ADDON_ID, (api) => { name: 'Component tests', title: ({ crashed, failed }) => crashed || failed ? 'Component tests failed' : 'Component tests', - description: ({ failed, running, watching, progress, crashed, details }) => { + description: ({ failed, running, watching, progress, crashed, error }) => { const [isModalOpen, setIsModalOpen] = useState(false); - const errorMessage = details?.error?.message; + const errorMessage = error?.message; let message: string | React.ReactNode = 'Not run'; @@ -106,7 +106,7 @@ addons.register(ADDON_ID, (api) => { ? `Testing... ${progress.numPassedTests}/${progress.numTotalTests}` : 'Starting...'; } else if (failed && !errorMessage) { - message = 'Component tests failed'; + message = ''; } else if (crashed || (failed && errorMessage)) { message = ( <> @@ -116,7 +116,7 @@ addons.register(ADDON_ID, (api) => { setIsModalOpen(true); }} > - {details?.error?.name || 'View full error'} + {error?.name || 'View full error'} ); @@ -177,7 +177,6 @@ addons.register(ADDON_ID, (api) => { ), } as Addon_TestProviderType<{ testResults: TestResult[]; - error?: { message: string; name: string }; }>); } diff --git a/code/addons/test/src/node/boot-test-runner.ts b/code/addons/test/src/node/boot-test-runner.ts index 6e7fe511947d..032be588b107 100644 --- a/code/addons/test/src/node/boot-test-runner.ts +++ b/code/addons/test/src/node/boot-test-runner.ts @@ -97,11 +97,13 @@ const bootTestRunner = async (channel: Channel, initEvent?: string, initArgs?: a killChild(); log(result.message); log(result.error); + // eslint-disable-next-line local-rules/no-uncategorized-errors + const error = new Error(`${result.message}\n${result.error}`); // Reject if the child process reports an error before it's ready if (!ready) { - reject(new Error(`${result.message}\n${result.error}`)); + reject(error); } else { - reportFatalError(result.error); + reportFatalError(error); } } else { channel.emit(result.type, ...result.args); diff --git a/code/addons/test/src/node/reporter.ts b/code/addons/test/src/node/reporter.ts index cc55ae75a5fb..c9a976ccf018 100644 --- a/code/addons/test/src/node/reporter.ts +++ b/code/addons/test/src/node/reporter.ts @@ -190,51 +190,55 @@ export class StorybookReporter implements Reporter { async onFinished() { const unhandledErrors = this.ctx.state.getUnhandledErrors(); - if (unhandledErrors?.length) { - this.testManager.reportFatalError( - `Vitest caught ${unhandledErrors.length} unhandled error${unhandledErrors?.length > 1 ? 's' : ''} during the test run.`, - unhandledErrors[0] - ); - } else { - const isCancelled = this.ctx.isCancelling; - const report = this.getProgressReport(Date.now()); + const isCancelled = this.ctx.isCancelling; + const report = this.getProgressReport(Date.now()); - const testSuiteFailures = report.details.testResults.filter( - (t) => t.status === 'failed' && t.results.length === 0 - ); + const testSuiteFailures = report.details.testResults.filter( + (t) => t.status === 'failed' && t.results.length === 0 + ); + + const reducedTestSuiteFailures = new Set(); - const reducedTestSuiteFailures = new Set(); + testSuiteFailures.forEach((t) => { + reducedTestSuiteFailures.add(t.message); + }); - testSuiteFailures.forEach((t) => { - reducedTestSuiteFailures.add(t.message); + if (isCancelled) { + this.sendReport({ + providerId: TEST_PROVIDER_ID, + status: 'cancelled', + ...report, }); + } else if (reducedTestSuiteFailures.size > 0 || unhandledErrors.length > 0) { + const error = + reducedTestSuiteFailures.size > 0 + ? { + name: `${reducedTestSuiteFailures.size} component ${reducedTestSuiteFailures.size === 1 ? 'test' : 'tests'} failed`, + message: Array.from(reducedTestSuiteFailures).reduce( + (acc, curr) => `${acc}\n${curr}`, + '' + ), + } + : { + name: `${unhandledErrors.length} unhandled error${unhandledErrors?.length > 1 ? 's' : ''}`, + message: unhandledErrors + .map((e, index) => `[${index}]: ${(e as any).stack || (e as any).message}`) + .join('\n----------\n'), + }; - if (isCancelled) { - this.sendReport({ - providerId: TEST_PROVIDER_ID, - status: 'cancelled', - ...report, - }); - } else if (reducedTestSuiteFailures.size > 0) { - const message = Array.from(reducedTestSuiteFailures).reduce( - (acc, curr) => `${acc}\n${curr}`, - '' - ); - this.sendReport({ - providerId: TEST_PROVIDER_ID, - status: 'failed', - error: { - name: `${reducedTestSuiteFailures.size} component ${reducedTestSuiteFailures.size === 1 ? 'test' : 'tests'} failed`, - message: message, - }, - }); - } else { - this.sendReport({ - providerId: TEST_PROVIDER_ID, - status: 'success', - ...report, - }); - } + this.sendReport({ + providerId: TEST_PROVIDER_ID, + status: 'failed', + details: report.details, + progress: report.progress, + error, + }); + } else { + this.sendReport({ + providerId: TEST_PROVIDER_ID, + status: 'success', + ...report, + }); } this.clearVitestState(); diff --git a/code/addons/test/src/preset.ts b/code/addons/test/src/preset.ts index 1d4203a3d5a5..685a56e2baf4 100644 --- a/code/addons/test/src/preset.ts +++ b/code/addons/test/src/preset.ts @@ -59,7 +59,6 @@ export const experimental_serverChannel = async (channel: Channel, options: Opti Information on how to upgrade here: ${picocolors.yellow('https://storybook.js.org/docs/get-started/frameworks/nextjs#with-vite')}\n `); } - return channel; } diff --git a/code/core/src/core-events/data/testing-module.ts b/code/core/src/core-events/data/testing-module.ts index fae5446f6e3a..d9e9640935a1 100644 --- a/code/core/src/core-events/data/testing-module.ts +++ b/code/core/src/core-events/data/testing-module.ts @@ -37,6 +37,8 @@ export type TestingModuleProgressReportPayload = | { providerId: TestProviderId; status: 'failed'; + progress?: TestingModuleProgressReportProgress; + details?: { [key: string]: any }; error: { name: string; message: string; diff --git a/code/core/src/manager/components/sidebar/SidebarBottom.tsx b/code/core/src/manager/components/sidebar/SidebarBottom.tsx index 48bf60a5f095..968eb2cd87bf 100644 --- a/code/core/src/manager/components/sidebar/SidebarBottom.tsx +++ b/code/core/src/manager/components/sidebar/SidebarBottom.tsx @@ -184,11 +184,11 @@ export const SidebarBottomBase = ({ api, notifications = [], status = {} }: Side updateTestProvider(providerId, { details, running: false, crashed: true, watching: false }); }; - const onProgressReport = ({ providerId, ...details }: TestingModuleProgressReportPayload) => { - if (details.status === 'failed') { - updateTestProvider(providerId, { details, running: false, failed: true }); + const onProgressReport = ({ providerId, ...result }: TestingModuleProgressReportPayload) => { + if (result.status === 'failed') { + updateTestProvider(providerId, { ...result, running: false, failed: true }); } else { - const update = { ...details, running: details.status === 'pending' }; + const update = { ...result, running: result.status === 'pending' }; updateTestProvider(providerId, update); const { mapStatusUpdate, ...state } = testProviders[providerId]; diff --git a/code/core/src/types/modules/addons.ts b/code/core/src/types/modules/addons.ts index 61473d42958c..2c995322b09d 100644 --- a/code/core/src/types/modules/addons.ts +++ b/code/core/src/types/modules/addons.ts @@ -474,7 +474,9 @@ export interface Addon_TestProviderType< name: string; title: (state: Addon_TestProviderState
) => ReactNode; description: (state: Addon_TestProviderState
) => ReactNode; - mapStatusUpdate?: (state: Addon_TestProviderState
) => API_StatusUpdate; + mapStatusUpdate?: ( + state: Addon_TestProviderState
+ ) => API_StatusUpdate | ((state: API_StatusState) => API_StatusUpdate); runnable?: boolean; watchable?: boolean; } @@ -489,6 +491,10 @@ export type Addon_TestProviderState
Date: Tue, 29 Oct 2024 17:41:06 +0100 Subject: [PATCH 06/11] Improve postinstall script for addon test --- code/addons/test/src/postinstall.ts | 100 +++++++++++++++------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/code/addons/test/src/postinstall.ts b/code/addons/test/src/postinstall.ts index e179b42fa1d2..9420d9ba3a38 100644 --- a/code/addons/test/src/postinstall.ts +++ b/code/addons/test/src/postinstall.ts @@ -53,43 +53,6 @@ export default async function postInstall(options: PostinstallOptions) { // if Vitest is installed, we use the same version to keep consistency across Vitest packages const vitestVersionToInstall = vitestVersionSpecifier ?? 'latest'; - const addonInteractionsName = '@storybook/addon-interactions'; - const interactionsAddon = info.addons.find((addon: string | { name: string }) => { - // account for addons as objects, as well as addons with PnP paths - const addonName = typeof addon === 'string' ? addon : addon.name; - return addonName.includes(addonInteractionsName); - }); - - if (!!interactionsAddon) { - let shouldUninstall = options.yes; - if (!options.yes) { - logger.plain(dedent` - We have detected that you're using ${addonInteractionsName}. - The Storybook test addon is a replacement for the interactions addon, so you must uninstall and unregister it in order to use the test addon correctly. This can be done automatically. - - More info: ${picocolors.yellow('https://storybook.js.org/docs/writing-tests/test-addon')} - `); - - const response = await prompts({ - type: 'confirm', - name: 'shouldUninstall', - message: `Would you like me to remove and unregister ${addonInteractionsName}?`, - initial: true, - }); - - shouldUninstall = response.shouldUninstall; - } - - if (shouldUninstall) { - await execa( - packageManager.getRemoteRunCommand(), - ['storybook', 'remove', addonInteractionsName, '--package-manager', options.packageManager], - { - shell: true, - } - ); - } - } const annotationsImport = [ '@storybook/nextjs', '@storybook/experimental-nextjs-vite', @@ -122,9 +85,9 @@ export default async function postInstall(options: PostinstallOptions) { `); } - if (coercedVitestVersion && !satisfies(coercedVitestVersion, '>=2.0.0')) { - reasons.push(` - • The addon requires Vitest 2.0.0 or later. You are currently using ${vitestVersionSpecifier}. + if (coercedVitestVersion && !satisfies(coercedVitestVersion, '>=2.1.0')) { + reasons.push(dedent` + • The addon requires Vitest 2.1.0 or later. You are currently using ${picocolors.bold(vitestVersionSpecifier)}. Please update your ${picocolors.bold(colors.pink('vitest'))} dependency and try again. `); } @@ -145,7 +108,7 @@ export default async function postInstall(options: PostinstallOptions) { ); reasons.push( dedent` - To roll back the installation, remove ${picocolors.bold(colors.pink(ADDON_NAME))} from the "addons" array + You can fix these issues and rerun the command to reinstall. If you wish to roll back the installation, remove ${picocolors.bold(colors.pink(ADDON_NAME))} from the "addons" array in your main Storybook config file and remove the dependency from your package.json file. ` ); @@ -180,6 +143,49 @@ export default async function postInstall(options: PostinstallOptions) { return; } + const addonInteractionsName = '@storybook/addon-interactions'; + const interactionsAddon = info.addons.find((addon: string | { name: string }) => { + // account for addons as objects, as well as addons with PnP paths + const addonName = typeof addon === 'string' ? addon : addon.name; + return addonName.includes(addonInteractionsName); + }); + + if (!!interactionsAddon) { + let shouldUninstall = options.yes; + if (!options.yes) { + printInfo( + '⚠️ Attention', + dedent` + We have detected that you're using ${addonInteractionsName}. + The Storybook test addon is a replacement for the interactions addon, so you must uninstall and unregister it in order to use the test addon correctly. This can be done automatically. + + More info: ${picocolors.cyan('https://storybook.js.org/docs/writing-tests/test-addon')} + ` + ); + + const response = await prompts({ + type: 'confirm', + name: 'shouldUninstall', + message: `Would you like me to remove and unregister ${addonInteractionsName}? Press N to abort the entire installation.`, + initial: true, + }); + + shouldUninstall = response.shouldUninstall; + } + + if (shouldUninstall) { + await execa( + packageManager.getRemoteRunCommand(), + ['storybook', 'remove', addonInteractionsName, '--package-manager', options.packageManager], + { + shell: true, + } + ); + } else { + return; + } + } + const vitestInfo = getVitestPluginInfo(info.frameworkPackageName); if (info.frameworkPackageName === '@storybook/nextjs') { @@ -317,6 +323,8 @@ export default async function postInstall(options: PostinstallOptions) { // If there's an existing config, we create a workspace file so we can run Storybook tests alongside. const extname = path.extname(rootConfig); const browserWorkspaceFile = path.resolve(dirname(rootConfig), `vitest.workspace${extname}`); + // to be set in vitest config + const vitestSetupFilePath = path.relative(path.dirname(browserWorkspaceFile), vitestSetupFile); logger.line(1); logger.plain(`${step} Creating a Vitest project workspace file:`); @@ -335,7 +343,7 @@ export default async function postInstall(options: PostinstallOptions) { extends: '${viteConfigFile ? relative(dirname(browserWorkspaceFile), viteConfigFile) : ''}', plugins: [ // See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest - storybookTest(),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall} + storybookTest({ configDir: '${options.configDir}' }),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall} ], test: { name: 'storybook', @@ -347,7 +355,7 @@ export default async function postInstall(options: PostinstallOptions) { }, // Make sure to adjust this pattern to match your stories files. include: ['**/*.stories.?(m)[jt]s?(x)'], - setupFiles: ['./.storybook/vitest.setup.ts'], + setupFiles: ['${vitestSetupFilePath}'], }, }, ]); @@ -356,6 +364,8 @@ export default async function postInstall(options: PostinstallOptions) { } else { // If there's no existing Vitest/Vite config, we create a new Vitest config file. const newVitestConfigFile = path.resolve('vitest.config.ts'); + // to be set in vitest config + const vitestSetupFilePath = path.relative(path.dirname(newVitestConfigFile), vitestSetupFile); logger.line(1); logger.plain(`${step} Creating a Vitest project config file:`); @@ -371,7 +381,7 @@ export default async function postInstall(options: PostinstallOptions) { export default defineConfig({ plugins: [ // See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest - storybookTest(),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall} + storybookTest({ configDir: '${options.configDir}' }),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall} ], test: { name: 'storybook', @@ -383,7 +393,7 @@ export default async function postInstall(options: PostinstallOptions) { }, // Make sure to adjust this pattern to match your stories files. include: ['**/*.stories.?(m)[jt]s?(x)'], - setupFiles: ['./.storybook/vitest.setup.ts'], + setupFiles: ['${vitestSetupFilePath}'], }, }); ` From b82bc68362bd475899c27fae67527d7cb2dbf367 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 29 Oct 2024 18:19:57 +0100 Subject: [PATCH 07/11] pass configDir down to storybook remove command --- code/addons/test/src/postinstall.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/code/addons/test/src/postinstall.ts b/code/addons/test/src/postinstall.ts index 9420d9ba3a38..78aaf0986df8 100644 --- a/code/addons/test/src/postinstall.ts +++ b/code/addons/test/src/postinstall.ts @@ -176,7 +176,15 @@ export default async function postInstall(options: PostinstallOptions) { if (shouldUninstall) { await execa( packageManager.getRemoteRunCommand(), - ['storybook', 'remove', addonInteractionsName, '--package-manager', options.packageManager], + [ + 'storybook', + 'remove', + addonInteractionsName, + '--package-manager', + options.packageManager, + '--config-dir', + options.configDir, + ], { shell: true, } From ee97b6532d39d4504935e598edfa55d1397f6d25 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 30 Oct 2024 10:22:23 +0100 Subject: [PATCH 08/11] Fix type issues --- code/addons/test/typings.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/addons/test/typings.d.ts b/code/addons/test/typings.d.ts index ec1d9d7d3808..d5de3255b176 100644 --- a/code/addons/test/typings.d.ts +++ b/code/addons/test/typings.d.ts @@ -5,3 +5,5 @@ interface ImportMetaEnv { interface ImportMeta { readonly env: ImportMetaEnv; } + +declare var STORYBOOK_BUILDER: string | undefined; From 9aac063cca0a828a3b3cba3249dcd02e7e2cf7be Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 30 Oct 2024 10:54:32 +0100 Subject: [PATCH 09/11] fix types --- code/addons/test/src/manager.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/addons/test/src/manager.tsx b/code/addons/test/src/manager.tsx index 37be0f132bce..82671fa0f386 100644 --- a/code/addons/test/src/manager.tsx +++ b/code/addons/test/src/manager.tsx @@ -80,7 +80,8 @@ const RelativeTime = ({ timestamp, testCount }: { timestamp: Date; testCount: nu }; addons.register(ADDON_ID, (api) => { - if (globalThis.STORYBOOK_BUILDER?.includes('vite')) { + const storybookBuilder = (globalThis as any).STORYBOOK_BUILDER || ''; + if (storybookBuilder.includes('vite')) { const openAddonPanel = () => { api.setSelectedPanel(PANEL_ID); api.togglePanel(true); From 5d433a4556c798941d0f671ff20c31b55a22cdf3 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Wed, 30 Oct 2024 11:32:59 +0100 Subject: [PATCH 10/11] Throttle Vitest progress updates more heavily --- code/addons/test/src/node/reporter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/addons/test/src/node/reporter.ts b/code/addons/test/src/node/reporter.ts index cc55ae75a5fb..6e66b5ca499e 100644 --- a/code/addons/test/src/node/reporter.ts +++ b/code/addons/test/src/node/reporter.ts @@ -65,7 +65,7 @@ export class StorybookReporter implements Reporter { sendReport: (payload: TestingModuleProgressReportPayload) => void; constructor(private testManager: TestManager) { - this.sendReport = throttle((payload) => this.testManager.sendProgressReport(payload), 200); + this.sendReport = throttle((payload) => this.testManager.sendProgressReport(payload), 1000); } onInit(ctx: Vitest) { From a2c7d35b5b718a7ac1df585cc53bc7b823e2c5ff Mon Sep 17 00:00:00 2001 From: storybook-bot <32066757+storybook-bot@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:16:00 +0000 Subject: [PATCH 11/11] Write changelog for 8.4.0-beta.4 [skip ci] --- CHANGELOG.prerelease.md | 9 +++++++++ code/package.json | 3 ++- docs/versions/next.json | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md index 5834c70763be..817d5dd0bbf9 100644 --- a/CHANGELOG.prerelease.md +++ b/CHANGELOG.prerelease.md @@ -1,3 +1,12 @@ +## 8.4.0-beta.4 + +- Addon Test: Improve Error Handling - [#29476](https://github.com/storybookjs/storybook/pull/29476), thanks @valentinpalkovic! +- Addon Test: Improve postinstall script - [#29479](https://github.com/storybookjs/storybook/pull/29479), thanks @yannbf! +- Addon Test: Throttle Vitest progress updates more heavily - [#29482](https://github.com/storybookjs/storybook/pull/29482), thanks @ghengeveld! +- CLI: Refactor NPMProxy error parsing logic - [#29459](https://github.com/storybookjs/storybook/pull/29459), thanks @yannbf! +- Core: Track test provider state in sessionStorage - [#29450](https://github.com/storybookjs/storybook/pull/29450), thanks @ghengeveld! +- Dependencies: Upgrade VTA to v3.2.0 to resolve peerDep conflict - [#29461](https://github.com/storybookjs/storybook/pull/29461), thanks @ghengeveld! + ## 8.4.0-beta.3 - Addon Test: Only register testing module in Vite projects - [#29472](https://github.com/storybookjs/storybook/pull/29472), thanks @yannbf! diff --git a/code/package.json b/code/package.json index 9c00bc5da6ef..9b9d7ec80717 100644 --- a/code/package.json +++ b/code/package.json @@ -293,5 +293,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "8.4.0-beta.4" } diff --git a/docs/versions/next.json b/docs/versions/next.json index f421e690e66a..cd3d3e08b10c 100644 --- a/docs/versions/next.json +++ b/docs/versions/next.json @@ -1 +1 @@ -{"version":"8.4.0-beta.3","info":{"plain":"- Addon Test: Only register testing module in Vite projects - [#29472](https://github.com/storybookjs/storybook/pull/29472), thanks @yannbf!"}} +{"version":"8.4.0-beta.4","info":{"plain":"- Addon Test: Improve Error Handling - [#29476](https://github.com/storybookjs/storybook/pull/29476), thanks @valentinpalkovic!\n- Addon Test: Improve postinstall script - [#29479](https://github.com/storybookjs/storybook/pull/29479), thanks @yannbf!\n- Addon Test: Throttle Vitest progress updates more heavily - [#29482](https://github.com/storybookjs/storybook/pull/29482), thanks @ghengeveld!\n- CLI: Refactor NPMProxy error parsing logic - [#29459](https://github.com/storybookjs/storybook/pull/29459), thanks @yannbf!\n- Core: Track test provider state in sessionStorage - [#29450](https://github.com/storybookjs/storybook/pull/29450), thanks @ghengeveld!\n- Dependencies: Upgrade VTA to v3.2.0 to resolve peerDep conflict - [#29461](https://github.com/storybookjs/storybook/pull/29461), thanks @ghengeveld!"}}