diff --git a/.nvmrc b/.nvmrc index 017faf90e766..ddeb00c1678b 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1,2 +1,2 @@ -22.21.1 +22.22.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 41efbe690ea2..07d000bf67b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 10.2.18 + +- Core: Correctly fallback to first detected vitest config file - [#33865](https://github.com/storybookjs/storybook/pull/33865), thanks @yannbf! +- Core: Fix error reporting in ManagerErrorBoundary - [#33915](https://github.com/storybookjs/storybook/pull/33915), thanks @ghengeveld! + ## 10.2.17 - Next.js: Add support for v16.2 - [#34046](https://github.com/storybookjs/storybook/pull/34046), thanks @valentinpalkovic! diff --git a/code/core/src/manager/components/error-boundary/ManagerErrorBoundary.stories.tsx b/code/core/src/manager/components/error-boundary/ManagerErrorBoundary.stories.tsx index 3d1cea253671..f12578d8c6f2 100644 --- a/code/core/src/manager/components/error-boundary/ManagerErrorBoundary.stories.tsx +++ b/code/core/src/manager/components/error-boundary/ManagerErrorBoundary.stories.tsx @@ -1,10 +1,33 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; -import { spyOn } from 'storybook/test'; +import { expect, fn, spyOn } from 'storybook/test'; import preview from '../../../../../.storybook/preview'; import { ManagerErrorBoundary } from './ManagerErrorBoundary'; +// Mocks for play assertions: set by decorator, asserted in play functions +let consoleErrorSpy: ReturnType; +const sendTelemetryErrorMock = fn(); + +// Stable wrapper: only cleanup in useEffect so teardown runs correctly with React Strict Mode. +// Setup must run synchronously in the decorator so the spy is in place before Story renders. +const RestoreGlobals = ({ + children, + originalSendTelemetryError, +}: { + children: React.ReactNode; + originalSendTelemetryError: typeof globalThis.sendTelemetryError; +}) => { + useEffect( + () => () => { + consoleErrorSpy.mockRestore(); + globalThis.sendTelemetryError = originalSendTelemetryError; + }, + [originalSendTelemetryError] + ); + return <>{children}; +}; + // Component that throws an error immediately when rendered const ThrowingComponent = ({ shouldThrow = true }: { shouldThrow?: boolean }) => { if (shouldThrow) { @@ -59,9 +82,15 @@ const meta = preview.meta({ }, decorators: [ (Story) => { - // Suppress console.error in stories to prevent noisy test output - spyOn(console, 'error').mockImplementation(() => {}); - return ; + consoleErrorSpy = spyOn(console, 'error').mockImplementation(() => {}); + sendTelemetryErrorMock.mockClear(); + const originalSendTelemetryError = globalThis.sendTelemetryError; + globalThis.sendTelemetryError = sendTelemetryErrorMock; + return ( + + + + ); }, ], }); @@ -74,6 +103,26 @@ export const WithError = meta.story({ ), + play: async ({ canvas }) => { + await expect(canvas.getByTestId('manager-error-boundary')).toBeInTheDocument(); + await expect(canvas.getByText('Something went wrong')).toBeInTheDocument(); + await expect( + canvas.getByText('This is a test error thrown by ThrowingComponent') + ).toBeInTheDocument(); + + await expect(consoleErrorSpy).toHaveBeenCalledWith( + 'Storybook Manager UI Error:', + expect.any(Error) + ); + await expect(consoleErrorSpy).toHaveBeenCalledWith('Component Stack:', expect.any(String)); + + await expect(sendTelemetryErrorMock).toHaveBeenCalledTimes(1); + await expect(sendTelemetryErrorMock).toHaveBeenCalledWith( + expect.objectContaining({ + message: 'This is a test error thrown by ThrowingComponent', + }) + ); + }, }); export const WithDeepStackTrace = meta.story({ @@ -93,6 +142,13 @@ export const WithoutError = meta.story({ ), + play: async ({ canvas }) => { + await expect(canvas.getByText('Everything is fine!')).toBeInTheDocument(); + await expect( + canvas.getByText('This content should render normally when there is no error.') + ).toBeInTheDocument(); + await expect(canvas.queryByTestId('manager-error-boundary')).not.toBeInTheDocument(); + }, }); export const InteractiveError = meta.story({ @@ -121,4 +177,19 @@ export const CustomErrorMessage = meta.story({ ); }, + play: async ({ canvas }) => { + await expect(canvas.getByTestId('manager-error-boundary')).toBeInTheDocument(); + await expect( + canvas.getByText( + 'Custom error: Unable to load addons configuration. Please check your manager.ts file.' + ) + ).toBeInTheDocument(); + + await expect(sendTelemetryErrorMock).toHaveBeenCalledWith( + expect.objectContaining({ + message: + 'Custom error: Unable to load addons configuration. Please check your manager.ts file.', + }) + ); + }, }); diff --git a/code/core/src/manager/components/error-boundary/ManagerErrorBoundary.tsx b/code/core/src/manager/components/error-boundary/ManagerErrorBoundary.tsx index 6aa356f2ca8c..cf4dd5605baa 100644 --- a/code/core/src/manager/components/error-boundary/ManagerErrorBoundary.tsx +++ b/code/core/src/manager/components/error-boundary/ManagerErrorBoundary.tsx @@ -196,6 +196,10 @@ export class ManagerErrorBoundary extends Component< console.error('Storybook Manager UI Error:', error); console.error('Component Stack:', errorInfo.componentStack); this.setState({ errorInfo }); + + if (typeof globalThis.sendTelemetryError === 'function') { + globalThis.sendTelemetryError(error); + } } render() { diff --git a/code/package.json b/code/package.json index eb67a5c8cbc7..59ed3270efae 100644 --- a/code/package.json +++ b/code/package.json @@ -220,5 +220,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "10.2.18" } diff --git a/docs/versions/latest.json b/docs/versions/latest.json index 93ca5a6b141e..5ec2eb17f3a3 100644 --- a/docs/versions/latest.json +++ b/docs/versions/latest.json @@ -1 +1 @@ -{"version":"10.2.17","info":{"plain":"- Next.js: Add support for v16.2 - [#34046](https://github.com/storybookjs/storybook/pull/34046), thanks @valentinpalkovic!"}} \ No newline at end of file +{"version":"10.2.18","info":{"plain":"- Core: Correctly fallback to first detected vitest config file - [#33865](https://github.com/storybookjs/storybook/pull/33865), thanks @yannbf!\n- Core: Fix error reporting in ManagerErrorBoundary - [#33915](https://github.com/storybookjs/storybook/pull/33915), thanks @ghengeveld!"}} \ No newline at end of file diff --git a/docs/versions/next.json b/docs/versions/next.json index a39b20674836..47d059281683 100644 --- a/docs/versions/next.json +++ b/docs/versions/next.json @@ -1 +1 @@ -{"version":"10.3.0-alpha.14","info":{"plain":"- CSF-Factories: Fix ConfigFile parser false warning on `definePreview({...}).type()` export default - [#33885](https://github.com/storybookjs/storybook/pull/33885), thanks @copilot-swe-agent!\n- Core: Add host/origin validation to requests and websocket connections - [#33835](https://github.com/storybookjs/storybook/pull/33835), thanks @ghengeveld!\n- Core: Storybook failed to load iframe.html when publishing - [#33896](https://github.com/storybookjs/storybook/pull/33896), thanks @danielalanbates!\n- Core: Zoom tool refinements - Hide reset button when value is initial - [#33635](https://github.com/storybookjs/storybook/pull/33635), thanks @superLipbalm!\n- Docs: Edit JSON button is now accessible at 320x256 viewport (WCAG 2.1 Reflow test) - [#33707](https://github.com/storybookjs/storybook/pull/33707), thanks @TheSeydiCharyyev!\n- Manager-API: Update refs sequentially in experimental_setFilter - [#33958](https://github.com/storybookjs/storybook/pull/33958), thanks @ia319!\n- UI: Allow direct kb/mouse actions on zoom tool button - [#33496](https://github.com/storybookjs/storybook/pull/33496), thanks @Sidnioulz!"}} \ No newline at end of file +{"version":"10.3.0-alpha.16","info":{"plain":"- A11y: Underline MDX links for WCAG SC 1.4.1 compliance - [#33139](https://github.com/storybookjs/storybook/pull/33139), thanks @NikhilChowdhury27!\n- Angular: Add moduleResolution: bundler to tsconfig - [#34085](https://github.com/storybookjs/storybook/pull/34085), thanks @valentinpalkovic!\n- Angular: only load webpack dependencies on demand - [#34043](https://github.com/storybookjs/storybook/pull/34043), thanks @sod!\n- CLI: Show multiple favicons warning as debug message - [#34069](https://github.com/storybookjs/storybook/pull/34069), thanks @remino!\n- Core: Fix error reporting in ManagerErrorBoundary - [#33915](https://github.com/storybookjs/storybook/pull/33915), thanks @ghengeveld!\n- Vite: Support Vite 8 - [#33788](https://github.com/storybookjs/storybook/pull/33788), thanks @valentinpalkovic!"}} \ No newline at end of file