diff --git a/.circleci/config.yml b/.circleci/config.yml index b2567e7d37f9..6a99d5190b61 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -878,10 +878,11 @@ workflows: parallelism: 4 requires: - create-sandboxes - - bench-sandboxes: - parallelism: 5 - requires: - - create-sandboxes +# TODO: don't forget to reenable this +# - bench-sandboxes: +# parallelism: 5 +# requires: +# - create-sandboxes - test-ui-testing-module: requires: - build @@ -965,10 +966,11 @@ workflows: - test-init-features: requires: - build - - bench-sandboxes: - parallelism: 5 - requires: - - create-sandboxes +# TODO: don't forget to reenable this +# - bench-sandboxes: +# parallelism: 5 +# requires: +# - create-sandboxes # TODO: reenable once we find out the source of flakyness # - test-runner-dev: # parallelism: 4 @@ -1059,10 +1061,11 @@ workflows: # --smoke-test is not supported for the angular builder right now # - "angular-cli" - "lit-vite-ts" - - bench-sandboxes: - parallelism: 5 - requires: - - create-sandboxes +# TODO: don't forget to reenable this +# - bench-sandboxes: +# parallelism: 5 +# requires: +# - create-sandboxes # TODO: reenable once we find out the source of flakyness # - test-runner-dev: diff --git a/CHANGELOG.md b/CHANGELOG.md index b9a6fe3bcef6..7cb041def8e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 8.6.4 + +- Manager: Add Content-Type to fix Cloud IDEs - [#30606](https://github.com/storybookjs/storybook/pull/30606), thanks @GCHQDeveloper548! +- Vite: Include `node_modules` in stats file - [#30711](https://github.com/storybookjs/storybook/pull/30711), thanks @JReinhold! + ## 8.6.3 - CSF Factories: Align addon-essentials import with other addons - [#30716](https://github.com/storybookjs/storybook/pull/30716), thanks @kasperpeulen! @@ -37,7 +42,6 @@ Here’s what’s new: - Addon-Test: Add telemetry data for Focused Tests - [#30568](https://github.com/storybookjs/storybook/pull/30568), thanks @JReinhold! - Addon-Test: Fix config and watch mode inconsistencies - [#30491](https://github.com/storybookjs/storybook/pull/30491), thanks @JReinhold! - Addon-Test: Fix console error in build mode - [#30625](https://github.com/storybookjs/storybook/pull/30625), thanks @JReinhold! -- Addon Test: Fix printing Date object in MethodCall for test/interactions log - [#30507](https://github.com/storybookjs/storybook/pull/30507), thanks @ghengeveld! - Addon-Test: Make sure that only one global portable story config is ever loaded - [#30582](https://github.com/storybookjs/storybook/pull/30582), thanks @kasperpeulen! - Angular: Fix accent character issue - [#30276](https://github.com/storybookjs/storybook/pull/30276), thanks @valentinpalkovic! - Angular: Support experimental zoneless mode - [#28657](https://github.com/storybookjs/storybook/pull/28657), thanks @anedomansky! @@ -46,7 +50,6 @@ Here’s what’s new: - Builder-Vite: Fix runtime and iframe 404 on first load - [#30567](https://github.com/storybookjs/storybook/pull/30567), thanks @valentinpalkovic! - Bun: Add support for text lock file - [#30160](https://github.com/storybookjs/storybook/pull/30160), thanks @Arctomachine! - Cleanup: Remove unused constants in viewport addon - [#30479](https://github.com/storybookjs/storybook/pull/30479), thanks @Guria! -- CLI: Add "features" question & auto-install test addon & improve test-addon compatibility - [#30202](https://github.com/storybookjs/storybook/pull/30202), thanks @ndelangen! - CLI: Don't initially select Documentation and Testing features - [#30599](https://github.com/storybookjs/storybook/pull/30599), thanks @ghengeveld! - CLI: Fix peer dep issues for npm users during upgrade - [#30616](https://github.com/storybookjs/storybook/pull/30616), thanks @valentinpalkovic! - CLI: Fix printing of selected features - [#30605](https://github.com/storybookjs/storybook/pull/30605), thanks @ghengeveld! diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md index 6b5ffbc6fcf9..cf388a310b1f 100644 --- a/CHANGELOG.prerelease.md +++ b/CHANGELOG.prerelease.md @@ -1,3 +1,21 @@ +## 9.0.0-alpha.3 + +- Addon A11y: Promote @storybook/global to full dependency - [#30723](https://github.com/storybookjs/storybook/pull/30723), thanks @mrginglymus! +- Addon Test: Improve unhandled error messages - [#30755](https://github.com/storybookjs/storybook/pull/30755), thanks @yannbf! +- Angular: Add @angular-devkit/build-angular to default installed pacakages in angular - [#30790](https://github.com/storybookjs/storybook/pull/30790), thanks @kasperpeulen! +- Automigrate: Disable `missingStorybookDependencies` for 9.0 - [#30769](https://github.com/storybookjs/storybook/pull/30769), thanks @ndelangen! +- CLI: Fix test install in RNW projects - [#30786](https://github.com/storybookjs/storybook/pull/30786), thanks @shilman! +- Core: Re-Export renderers from frameworks - [#30771](https://github.com/storybookjs/storybook/pull/30771), thanks @ndelangen! +- Core: Replace 'min' instead of 'm' in printDuration - [#30668](https://github.com/storybookjs/storybook/pull/30668), thanks @wlewis-formative! +- Migration: Add auto-automigration for merged packages - [#30753](https://github.com/storybookjs/storybook/pull/30753), thanks @ndelangen! +- Next.js: Upgrade image-size to 2.0 - [#30741](https://github.com/storybookjs/storybook/pull/30741), thanks @valentinpalkovic! +- Next.js: Use latest version when init in empty directory - [#30659](https://github.com/storybookjs/storybook/pull/30659), thanks @valentinpalkovic! +- Svelte: Fix Vite crashing on virtual module imports - [#26838](https://github.com/storybookjs/storybook/pull/26838), thanks @rChaoz! +- Svelte: Fix automatic argTypes inference coming up empty with `svelte2tsx@0.7.35` - [#30784](https://github.com/storybookjs/storybook/pull/30784), thanks @JReinhold! +- Svelte: Pin svelte2tsx to solve argType regression - [#30783](https://github.com/storybookjs/storybook/pull/30783), thanks @kasperpeulen! +- Test: Move `@storybook/test` into `storybook/test` - [#30742](https://github.com/storybookjs/storybook/pull/30742), thanks @valentinpalkovic! +- Universal Store: Don't use `crypto.randomUUID` - [#30781](https://github.com/storybookjs/storybook/pull/30781), thanks @JReinhold! + ## 9.0.0-alpha.2 - AutoBlocker: Add major version upgrade blocker - [#30714](https://github.com/storybookjs/storybook/pull/30714), thanks @ndelangen! diff --git a/MIGRATION.md b/MIGRATION.md index 3b063eff396a..8bde2228682e 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,6 +1,7 @@

Migration

- [From version 8.x to 9.0.0](#from-version-8x-to-900) + - [Dropped support for legacy packages](#dropped-support-for-legacy-packages) - [Dropped support for TypeScript \< 4.9](#dropped-support-for-typescript--49) - [Test addon renamed from experimental to stable](#test-addon-renamed-from-experimental-to-stable) - [From version 8.5.x to 8.6.x](#from-version-85x-to-86x) @@ -436,6 +437,45 @@ ## From version 8.x to 9.0.0 +### Dropped support for legacy packages + +The following packages are no longer published as part of `9.0.0`: +The following packages have been consolidated into the main `storybook` package: + +| Old Package | New Path | +| ---------------------- | ------------------------------ | +| @storybook/manager-api | storybook/manager-api | +| @storybook/preview-api | storybook/preview-api | +| @storybook/theming | storybook/theming | +| @storybook/test | storybook/test | + +Please un-install these packages, and ensure you have the `storybook` package installed. + +Replace any imports with the path listed in the second column. + +Additionally the following packages were also consolidated and placed under a `/internal` sub-path, to indicate they are for internal usage only. +If you're depending on these packages, they will continue to work for `9.0`, but they will likely be removed in `10.0`. + +| Old Package | New Path | +| -------------------------- | ---------------------------------- | +| @storybook/channels | storybook/internal/channels | +| @storybook/client-logger | storybook/internal/client-logger | +| @storybook/core-common | storybook/internal/common | +| @storybook/core-events | storybook/internal/core-events | +| @storybook/csf-tools | storybook/internal/csf-tools | +| @storybook/docs-tools | storybook/internal/docs-tools | +| @storybook/node-logger | storybook/internal/node-logger | +| @storybook/router | storybook/internal/router | +| @storybook/telemetry | storybook/internal/telemetry | +| @storybook/types | storybook/internal/types | +| @storybook/manager | storybook/internal/manager | +| @storybook/preview | storybook/internal/preview | +| @storybook/core-server | storybook/internal/core-server | +| @storybook/builder-manager | storybook/internal/builder-manager | +| @storybook/components | storybook/internal/components | + +Addon authors may continue to use the internal packages, there is currently not yet any replacement. + ### Dropped support for TypeScript < 4.9 Storybook now requires TypeScript 4.9 or later. If you're using an older version of TypeScript, you'll need to upgrade to continue using Storybook. diff --git a/code/.storybook/bench.stories.tsx b/code/.storybook/bench.stories.tsx index 3b9055905aac..98578869b483 100644 --- a/code/.storybook/bench.stories.tsx +++ b/code/.storybook/bench.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta } from '@storybook/react'; +import type { Meta } from '@storybook/react-vite'; // @ts-expect-error - TS doesn't know about import.meta.glob from Vite const allMetafiles = import.meta.glob([ diff --git a/code/.storybook/preview.tsx b/code/.storybook/preview.tsx index 2a3d237ce611..24924feaf9f3 100644 --- a/code/.storybook/preview.tsx +++ b/code/.storybook/preview.tsx @@ -16,8 +16,8 @@ import { import { DocsContext } from '@storybook/blocks'; import { global } from '@storybook/global'; -import type { Decorator, Loader, ReactRenderer } from '@storybook/react'; +import type { Decorator, Loader, ReactRenderer } from '@storybook/react-vite'; // TODO add empty preview // import * as storysource from '@storybook/addon-storysource'; // import * as designs from '@storybook/addon-designs/preview'; diff --git a/code/.storybook/storybook.setup.ts b/code/.storybook/storybook.setup.ts index 80160218a314..833e21c50ac5 100644 --- a/code/.storybook/storybook.setup.ts +++ b/code/.storybook/storybook.setup.ts @@ -1,7 +1,8 @@ import { beforeAll, vi, expect as vitestExpect } from 'vitest'; import { setProjectAnnotations } from '@storybook/react'; -import { userEvent as storybookEvent, expect as storybookExpect } from '@storybook/test'; + +import { userEvent as storybookEvent, expect as storybookExpect } from 'storybook/test'; import preview from './preview'; diff --git a/code/.storybook/vitest.config.ts b/code/.storybook/vitest.config.ts index 22f3d5f620c3..e3d04ba0d378 100644 --- a/code/.storybook/vitest.config.ts +++ b/code/.storybook/vitest.config.ts @@ -1,5 +1,7 @@ import { defaultExclude, defineProject, mergeConfig } from 'vitest/config'; +import { storybookTest } from '@storybook/addon-test/vitest-plugin'; + import Inspect from 'vite-plugin-inspect'; import { vitestCommonConfig } from '../vitest.workspace'; @@ -22,14 +24,12 @@ export default mergeConfig( // @ts-expect-error added this because of testNamePattern below defineProject({ plugins: [ - import('@storybook/addon-test/vitest-plugin').then(({ storybookTest }) => - storybookTest({ - configDir: __dirname, - tags: { - include: ['vitest'], - }, - }) - ), + storybookTest({ + configDir: __dirname, + tags: { + include: ['vitest'], + }, + }), ...extraPlugins, ], test: { @@ -40,7 +40,7 @@ export default mergeConfig( '**/__mockdata__/**', '../**/__mockdata__/**', '**/Zoom.stories.tsx', // expected to fail in Vitest because of fetching /iframe.html to cause ECONNREFUSED - '**/lib/blocks/src/**', // won't work because of https://github.com/storybookjs/storybook/issues/29783 + '../lib/blocks/src/**', // won't work because of https://github.com/storybookjs/storybook/issues/29783 ], // TODO: bring this back once portable stories support storybook/internal/preview-api hooks // @ts-expect-error this type does not exist but the property does! diff --git a/code/addons/a11y/package.json b/code/addons/a11y/package.json index 4264691eabd7..3c956180d7c9 100644 --- a/code/addons/a11y/package.json +++ b/code/addons/a11y/package.json @@ -67,11 +67,10 @@ }, "dependencies": { "@storybook/addon-highlight": "workspace:*", - "@storybook/test": "workspace:*", + "@storybook/global": "^5.0.0", "axe-core": "^4.2.0" }, "devDependencies": { - "@storybook/global": "^5.0.0", "@storybook/icons": "^1.2.12", "@testing-library/react": "^14.0.0", "execa": "^9.5.2", diff --git a/code/addons/a11y/src/components/A11YPanel.stories.tsx b/code/addons/a11y/src/components/A11YPanel.stories.tsx index 701b5a509338..accbca14f3f9 100644 --- a/code/addons/a11y/src/components/A11YPanel.stories.tsx +++ b/code/addons/a11y/src/components/A11YPanel.stories.tsx @@ -3,10 +3,10 @@ import React from 'react'; import { ManagerContext } from 'storybook/internal/manager-api'; import { ThemeProvider, convert, themes } from 'storybook/internal/theming'; -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import type axe from 'axe-core'; +import { fn } from 'storybook/test'; import { A11YPanel } from './A11YPanel'; import { A11yContext } from './A11yContext'; diff --git a/code/addons/a11y/src/components/TestDiscrepancyMessage.stories.tsx b/code/addons/a11y/src/components/TestDiscrepancyMessage.stories.tsx index 578c2bbac792..352edf11ca74 100644 --- a/code/addons/a11y/src/components/TestDiscrepancyMessage.stories.tsx +++ b/code/addons/a11y/src/components/TestDiscrepancyMessage.stories.tsx @@ -2,8 +2,9 @@ import React from 'react'; import { ManagerContext } from 'storybook/internal/manager-api'; -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { TestDiscrepancyMessage } from './TestDiscrepancyMessage'; diff --git a/code/addons/a11y/src/preview.tsx b/code/addons/a11y/src/preview.tsx index 9b8a7598d6de..4a0704ed3eb1 100644 --- a/code/addons/a11y/src/preview.tsx +++ b/code/addons/a11y/src/preview.tsx @@ -1,6 +1,6 @@ import type { AfterEach } from 'storybook/internal/types'; -import { expect } from '@storybook/test'; +import { expect } from 'storybook/test'; import { run } from './a11yRunner'; import type { A11yParameters } from './params'; @@ -64,7 +64,7 @@ export const experimental_afterEach: AfterEach = async ({ vitestMatchersExtended = true; } - // @ts-expect-error - todo - fix type extension of expect from @storybook/test + // @ts-expect-error - todo - fix type extension of expect from storybook/test expect(result).toHaveNoViolations(); } } diff --git a/code/addons/actions/package.json b/code/addons/actions/package.json index 4efd2af83f94..58b88b30fe02 100644 --- a/code/addons/actions/package.json +++ b/code/addons/actions/package.json @@ -74,7 +74,6 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@storybook/test": "workspace:*", "react": "^18.2.0", "react-dom": "^18.2.0", "react-inspector": "^6.0.0", diff --git a/code/addons/actions/src/loaders.ts b/code/addons/actions/src/loaders.ts index 118d5c0b1b7e..60202ec36928 100644 --- a/code/addons/actions/src/loaders.ts +++ b/code/addons/actions/src/loaders.ts @@ -2,7 +2,8 @@ import type { LoaderFunction } from 'storybook/internal/types'; import { global } from '@storybook/global'; -import type { onMockCall as onMockCallType } from '@storybook/test'; + +import type { onMockCall as onMockCallType } from 'storybook/test'; import { action } from './runtime'; diff --git a/code/addons/actions/template/stories/spies.stories.ts b/code/addons/actions/template/stories/spies.stories.ts index 9d84cae3d361..d3f0ed191087 100644 --- a/code/addons/actions/template/stories/spies.stories.ts +++ b/code/addons/actions/template/stories/spies.stories.ts @@ -1,5 +1,6 @@ import { global as globalThis } from '@storybook/global'; -import { spyOn } from '@storybook/test'; + +import { spyOn } from 'storybook/test'; const meta = { component: globalThis.Components.Button, diff --git a/code/addons/controls/src/SaveStory.stories.tsx b/code/addons/controls/src/SaveStory.stories.tsx index 9c39f6746e04..99d64fc7e28e 100644 --- a/code/addons/controls/src/SaveStory.stories.tsx +++ b/code/addons/controls/src/SaveStory.stories.tsx @@ -1,10 +1,11 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fireEvent, fn, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; +import { expect, fireEvent, fn, userEvent, within } from 'storybook/test'; + import { SaveStory } from './SaveStory'; const meta = { diff --git a/code/addons/docs/template/stories/docs2/resolved-react.stories.ts b/code/addons/docs/template/stories/docs2/resolved-react.stories.ts index 75e3d480ca98..43564cf4638a 100644 --- a/code/addons/docs/template/stories/docs2/resolved-react.stories.ts +++ b/code/addons/docs/template/stories/docs2/resolved-react.stories.ts @@ -2,7 +2,7 @@ import * as ReactExport from 'react'; import * as ReactDom from 'react-dom'; import * as ReactDomServer from 'react-dom/server'; -import { expect, within } from '@storybook/test'; +import { expect, within } from 'storybook/test'; /** * This component is used to display the resolved version of React and its related packages. As long diff --git a/code/addons/docs/template/stories/docspage/autoplay.stories.ts b/code/addons/docs/template/stories/docspage/autoplay.stories.ts index 03d1388f2fb6..e96aeeaf4174 100644 --- a/code/addons/docs/template/stories/docspage/autoplay.stories.ts +++ b/code/addons/docs/template/stories/docspage/autoplay.stories.ts @@ -1,4 +1,4 @@ -import { expect, within } from '@storybook/test'; +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/addons/docs/template/stories/docspage/basic.stories.ts b/code/addons/docs/template/stories/docspage/basic.stories.ts index a9ea37650fc9..a21d7ab3675b 100644 --- a/code/addons/docs/template/stories/docspage/basic.stories.ts +++ b/code/addons/docs/template/stories/docspage/basic.stories.ts @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; export default { component: globalThis.Components.Button, diff --git a/code/addons/interactions/README.md b/code/addons/interactions/README.md index 8e97267a65d3..bd6895851ccd 100644 --- a/code/addons/interactions/README.md +++ b/code/addons/interactions/README.md @@ -9,7 +9,7 @@ Storybook Addon Interactions enables visual debugging of interactions and tests Install this addon by adding the `@storybook/addon-interactions` dependency: ```sh -yarn add -D @storybook/addon-interactions @storybook/test +yarn add -D @storybook/addon-interactions ``` within `.storybook/main.js`: @@ -24,10 +24,10 @@ Note that `@storybook/addon-interactions` must be listed **after** `@storybook/a ## Usage -Interactions relies on "instrumented" versions of Vitest and Testing Library, that you import from `@storybook/test` instead of their original package. You can then use these libraries in your `play` function. +Interactions relies on "instrumented" versions of Vitest and Testing Library, that you import from `storybook/test` instead of their original package. You can then use these libraries in your `play` function. ```js -import { expect, fn, userEvent, within } from '@storybook/test'; +import { expect, fn, userEvent, within } from 'storybook/test'; import { Button } from './Button'; export default { diff --git a/code/addons/interactions/package.json b/code/addons/interactions/package.json index 512f172586a9..bd35a619b7ea 100644 --- a/code/addons/interactions/package.json +++ b/code/addons/interactions/package.json @@ -63,7 +63,6 @@ }, "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/test": "workspace:*", "polished": "^4.2.2", "ts-dedent": "^2.2.0" }, diff --git a/code/addons/interactions/src/components/Interaction.stories.tsx b/code/addons/interactions/src/components/Interaction.stories.tsx index 64f43a8cef7f..4526cdcebab2 100644 --- a/code/addons/interactions/src/components/Interaction.stories.tsx +++ b/code/addons/interactions/src/components/Interaction.stories.tsx @@ -1,7 +1,8 @@ import { CallStates } from 'storybook/internal/instrumenter'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, userEvent, within } from 'storybook/test'; import { getCalls } from '../mocks'; import { Interaction } from './Interaction'; diff --git a/code/addons/interactions/src/components/InteractionsPanel.stories.tsx b/code/addons/interactions/src/components/InteractionsPanel.stories.tsx index 8d6d7cd9f3f1..20128d9f8341 100644 --- a/code/addons/interactions/src/components/InteractionsPanel.stories.tsx +++ b/code/addons/interactions/src/components/InteractionsPanel.stories.tsx @@ -3,8 +3,9 @@ import React from 'react'; import { CallStates } from 'storybook/internal/instrumenter'; import { styled } from 'storybook/internal/theming'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, waitFor, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, userEvent, waitFor, within } from 'storybook/test'; import { isChromatic } from '../../../../.storybook/isChromatic'; import { getCalls, getInteractions } from '../mocks'; diff --git a/code/addons/interactions/src/preview.ts b/code/addons/interactions/src/preview.ts index 635e50ccedb3..227fef876d04 100644 --- a/code/addons/interactions/src/preview.ts +++ b/code/addons/interactions/src/preview.ts @@ -3,7 +3,7 @@ import type { PlayFunction, StepLabel, StepRunner, StoryContext } from 'storyboo // This makes sure that storybook test loaders are always loaded when addon-interactions is used // For 9.0 we want to merge storybook/test and addon-interactions into one addon. -import '@storybook/test'; +import 'storybook/test'; import type { InteractionsParameters } from './types'; diff --git a/code/addons/interactions/template/stories/basics.stories.ts b/code/addons/interactions/template/stories/basics.stories.ts index 2db5f0e016f3..a1cb4ce7d41b 100644 --- a/code/addons/interactions/template/stories/basics.stories.ts +++ b/code/addons/interactions/template/stories/basics.stories.ts @@ -1,4 +1,5 @@ import { global as globalThis } from '@storybook/global'; + import { expect, fireEvent, @@ -7,7 +8,7 @@ import { waitFor, waitForElementToBeRemoved, within, -} from '@storybook/test'; +} from 'storybook/test'; export default { component: globalThis.Components.Form, diff --git a/code/addons/interactions/template/stories/unhandled-errors.stories.ts b/code/addons/interactions/template/stories/unhandled-errors.stories.ts index b9be0df743e0..d5c396b71683 100644 --- a/code/addons/interactions/template/stories/unhandled-errors.stories.ts +++ b/code/addons/interactions/template/stories/unhandled-errors.stories.ts @@ -1,5 +1,6 @@ import { global as globalThis } from '@storybook/global'; -import { userEvent, within } from '@storybook/test'; + +import { userEvent, within } from 'storybook/test'; export default { component: globalThis.Components.Button, diff --git a/code/addons/onboarding/package.json b/code/addons/onboarding/package.json index 5193be12fff0..441cfbb600e6 100644 --- a/code/addons/onboarding/package.json +++ b/code/addons/onboarding/package.json @@ -48,7 +48,6 @@ "@neoconfetti/react": "^1.0.0", "@radix-ui/react-dialog": "^1.0.5", "@storybook/icons": "^1.2.12", - "@storybook/react": "workspace:*", "framer-motion": "^11.0.3", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/code/addons/onboarding/src/components/Button/Button.stories.tsx b/code/addons/onboarding/src/components/Button/Button.stories.tsx index 1d4396a29c63..0c9e0c9cbb23 100644 --- a/code/addons/onboarding/src/components/Button/Button.stories.tsx +++ b/code/addons/onboarding/src/components/Button/Button.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/addons/onboarding/src/components/Confetti/Confetti.stories.tsx b/code/addons/onboarding/src/components/Confetti/Confetti.stories.tsx index 3540aadc2a85..8de0444a7386 100644 --- a/code/addons/onboarding/src/components/Confetti/Confetti.stories.tsx +++ b/code/addons/onboarding/src/components/Confetti/Confetti.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Confetti } from './Confetti'; diff --git a/code/addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx b/code/addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx index 7cb0c52b0113..02f8cf3dc209 100644 --- a/code/addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx +++ b/code/addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx @@ -1,7 +1,8 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, waitFor, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, waitFor, within } from 'storybook/test'; import { HighlightElement } from './HighlightElement'; diff --git a/code/addons/onboarding/src/components/List/List.stories.tsx b/code/addons/onboarding/src/components/List/List.stories.tsx index 8e7667d8a12e..1065ec1ae97b 100644 --- a/code/addons/onboarding/src/components/List/List.stories.tsx +++ b/code/addons/onboarding/src/components/List/List.stories.tsx @@ -1,7 +1,8 @@ import React, { useState } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, waitFor, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, userEvent, waitFor, within } from 'storybook/test'; import { List } from './List'; import { ListItem } from './ListItem/ListItem'; diff --git a/code/addons/onboarding/src/features/GuidedTour/GuidedTour.stories.tsx b/code/addons/onboarding/src/features/GuidedTour/GuidedTour.stories.tsx index c35a02830a5e..3ddb94096528 100644 --- a/code/addons/onboarding/src/features/GuidedTour/GuidedTour.stories.tsx +++ b/code/addons/onboarding/src/features/GuidedTour/GuidedTour.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { GuidedTour } from './GuidedTour'; diff --git a/code/addons/onboarding/src/features/SplashScreen/SplashScreen.stories.tsx b/code/addons/onboarding/src/features/SplashScreen/SplashScreen.stories.tsx index 7e83cd3e6558..a7184e39158c 100644 --- a/code/addons/onboarding/src/features/SplashScreen/SplashScreen.stories.tsx +++ b/code/addons/onboarding/src/features/SplashScreen/SplashScreen.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { SplashScreen } from './SplashScreen'; diff --git a/code/addons/test/package.json b/code/addons/test/package.json index 72ef2734da17..9be7b02b5aec 100644 --- a/code/addons/test/package.json +++ b/code/addons/test/package.json @@ -100,7 +100,6 @@ "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^1.2.12", - "@storybook/test": "workspace:*", "polished": "^4.2.2", "prompts": "^2.4.0", "ts-dedent": "^2.2.0" @@ -110,8 +109,8 @@ "@types/istanbul-lib-report": "^3.0.3", "@types/node": "^22.0.0", "@types/semver": "^7", - "@vitest/browser": "^3.0.2", - "@vitest/runner": "^3.0.2", + "@vitest/browser": "^3.0.8", + "@vitest/runner": "^3.0.8", "ansi-to-html": "^0.7.2", "boxen": "^8.0.1", "es-toolkit": "^1.22.0", @@ -131,7 +130,7 @@ "tree-kill": "^1.2.2", "ts-dedent": "^2.2.0", "typescript": "^5.7.3", - "vitest": "^3.0.2" + "vitest": "^3.0.8" }, "peerDependencies": { "@vitest/browser": "^2.1.1 || ^3.0.0", diff --git a/code/addons/test/src/components/GlobalErrorModal.stories.tsx b/code/addons/test/src/components/GlobalErrorModal.stories.tsx index 773ff178f17a..8d10b8d7d9a4 100644 --- a/code/addons/test/src/components/GlobalErrorModal.stories.tsx +++ b/code/addons/test/src/components/GlobalErrorModal.stories.tsx @@ -2,9 +2,9 @@ import React, { useState } from 'react'; import { ManagerContext } from 'storybook/internal/manager-api'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fn, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, fn, userEvent, within } from 'storybook/test'; import dedent from 'ts-dedent'; import { GlobalErrorContext, GlobalErrorModal } from './GlobalErrorModal'; diff --git a/code/addons/test/src/components/Interaction.stories.tsx b/code/addons/test/src/components/Interaction.stories.tsx index 64f43a8cef7f..4526cdcebab2 100644 --- a/code/addons/test/src/components/Interaction.stories.tsx +++ b/code/addons/test/src/components/Interaction.stories.tsx @@ -1,7 +1,8 @@ import { CallStates } from 'storybook/internal/instrumenter'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, userEvent, within } from 'storybook/test'; import { getCalls } from '../mocks'; import { Interaction } from './Interaction'; diff --git a/code/addons/test/src/components/InteractionsPanel.stories.tsx b/code/addons/test/src/components/InteractionsPanel.stories.tsx index 2efaa5d96c51..a4509f49f8e4 100644 --- a/code/addons/test/src/components/InteractionsPanel.stories.tsx +++ b/code/addons/test/src/components/InteractionsPanel.stories.tsx @@ -4,8 +4,9 @@ import { CallStates } from 'storybook/internal/instrumenter'; import { ManagerContext } from 'storybook/internal/manager-api'; import { styled } from 'storybook/internal/theming'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fn, userEvent, waitFor, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, fn, userEvent, waitFor, within } from 'storybook/test'; import { isChromatic } from '../../../../.storybook/isChromatic'; import { getCalls, getInteractions } from '../mocks'; diff --git a/code/addons/test/src/components/RelativeTime.stories.tsx b/code/addons/test/src/components/RelativeTime.stories.tsx index 4d3c6af0f6d8..aecc461c8b74 100644 --- a/code/addons/test/src/components/RelativeTime.stories.tsx +++ b/code/addons/test/src/components/RelativeTime.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { RelativeTime } from './RelativeTime'; diff --git a/code/addons/test/src/components/TestDiscrepancyMessage.stories.tsx b/code/addons/test/src/components/TestDiscrepancyMessage.stories.tsx index d6ca6aa83201..ab535bb80f1d 100644 --- a/code/addons/test/src/components/TestDiscrepancyMessage.stories.tsx +++ b/code/addons/test/src/components/TestDiscrepancyMessage.stories.tsx @@ -3,8 +3,9 @@ import React from 'react'; import { CallStates } from 'storybook/internal/instrumenter'; import { ManagerContext } from 'storybook/internal/manager-api'; -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { TestDiscrepancyMessage } from './TestDiscrepancyMessage'; diff --git a/code/addons/test/src/components/TestProviderRender.stories.tsx b/code/addons/test/src/components/TestProviderRender.stories.tsx index 40097eae1ddc..058a7187fc47 100644 --- a/code/addons/test/src/components/TestProviderRender.stories.tsx +++ b/code/addons/test/src/components/TestProviderRender.stories.tsx @@ -5,8 +5,9 @@ import { ManagerContext } from 'storybook/internal/manager-api'; import { styled } from 'storybook/internal/theming'; import { Addon_TypesEnum } from 'storybook/internal/types'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, fn } from 'storybook/test'; import { type Details, storeOptions } from '../constants'; import { store as mockStore } from '../manager-store.mock'; diff --git a/code/addons/test/src/components/TestStatusIcon.stories.tsx b/code/addons/test/src/components/TestStatusIcon.stories.tsx index e46d22e015d6..6d6bdd037f1a 100644 --- a/code/addons/test/src/components/TestStatusIcon.stories.tsx +++ b/code/addons/test/src/components/TestStatusIcon.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { TestStatusIcon } from './TestStatusIcon'; diff --git a/code/addons/test/src/index.ts b/code/addons/test/src/index.ts index 0fcea514a601..296f896ee669 100644 --- a/code/addons/test/src/index.ts +++ b/code/addons/test/src/index.ts @@ -1,16 +1,7 @@ import { definePreview } from 'storybook/internal/preview-api'; import * as addonAnnotations from './preview'; -import type { storybookTest as storybookTestImport } from './vitest-plugin'; export default () => definePreview(addonAnnotations); export type { TestParameters } from './types'; - -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore-error - this is a hack to make the module's sub-path augmentable -declare module '@storybook/addon-test/vitest-plugin' { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore-error - this is a hack to make the module's sub-path augmentable - export const storybookTest: typeof storybookTestImport; -} diff --git a/code/addons/test/src/manager-store.mock.ts b/code/addons/test/src/manager-store.mock.ts index 9b64e314b039..cc4d18ef5108 100644 --- a/code/addons/test/src/manager-store.mock.ts +++ b/code/addons/test/src/manager-store.mock.ts @@ -1,6 +1,6 @@ import { experimental_MockUniversalStore } from 'storybook/internal/manager-api'; -import * as testUtils from '@storybook/test'; +import * as testUtils from 'storybook/test'; import { storeOptions } from './constants'; diff --git a/code/addons/test/src/node/reporter.ts b/code/addons/test/src/node/reporter.ts index eb0c31a38474..93e6d25d50b4 100644 --- a/code/addons/test/src/node/reporter.ts +++ b/code/addons/test/src/node/reporter.ts @@ -13,6 +13,7 @@ import type { API_StatusUpdate } from 'storybook/internal/types'; import type { Suite } from '@vitest/runner'; import { throttle } from 'es-toolkit'; import { satisfies } from 'semver'; +import { dedent } from 'ts-dedent'; import { TEST_PROVIDER_ID } from '../constants'; import type { TestManager } from './test-manager'; @@ -60,6 +61,36 @@ const isVitest3OrLater = vitestVersion ? satisfies(vitestVersion, '>=3.0.0-beta.3', { includePrerelease: true }) : false; +interface VitestError extends Error { + VITEST_TEST_PATH?: string; + VITEST_TEST_NAME?: string; +} + +const getErrorOrigin = (error: VitestError): string => { + const parts: string[] = []; + + if (error.VITEST_TEST_PATH) { + parts.push( + dedent` + \nThis error originated in "${error.VITEST_TEST_PATH}". It doesn't mean the error was thrown inside the file itself, but while it was running. + ` + ); + } + + if (error.VITEST_TEST_NAME) { + parts.push( + dedent` + The latest test that might've caused the error is "${error.VITEST_TEST_NAME}". + It might mean one of the following: + - The error was thrown, while Vitest was running this test. + - If the error occurred after the test had been completed, this was the last documented test before it was thrown. + ` + ); + } + + return parts.join('\n'); +}; + export class StorybookReporter implements Reporter { testStatusData: API_StatusUpdate = {}; @@ -219,6 +250,14 @@ export class StorybookReporter implements Reporter { async onFinished() { const unhandledErrors = this.ctx.state.getUnhandledErrors(); + unhandledErrors.forEach((e: unknown) => { + const error = e as VitestError; + const origin = getErrorOrigin(error); + if (origin) { + error.message = `${error.message}\n${origin}`; + error.stack = `${error.stack}\n${origin}`; + } + }); const isCancelled = isVitest3OrLater ? this.testManager.vitestManager.isCancelling @@ -256,7 +295,7 @@ export class StorybookReporter implements Reporter { 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'), + .join('\n\n----------\n\n'), }; this.sendReport({ diff --git a/code/addons/test/src/preview.ts b/code/addons/test/src/preview.ts index 2a78c0fde790..ac1b58934881 100644 --- a/code/addons/test/src/preview.ts +++ b/code/addons/test/src/preview.ts @@ -3,7 +3,7 @@ import type { PlayFunction, StepLabel, StoryContext } from 'storybook/internal/t // This makes sure that storybook test loaders are always loaded when addon-interactions is used // For 9.0 we want to merge storybook/test and addon-interactions into one addon. -import '@storybook/test'; +import 'storybook/test'; export const { step: runStep } = instrument( { diff --git a/code/addons/test/template/stories/basics.stories.ts b/code/addons/test/template/stories/basics.stories.ts index 2db5f0e016f3..a1cb4ce7d41b 100644 --- a/code/addons/test/template/stories/basics.stories.ts +++ b/code/addons/test/template/stories/basics.stories.ts @@ -1,4 +1,5 @@ import { global as globalThis } from '@storybook/global'; + import { expect, fireEvent, @@ -7,7 +8,7 @@ import { waitFor, waitForElementToBeRemoved, within, -} from '@storybook/test'; +} from 'storybook/test'; export default { component: globalThis.Components.Form, diff --git a/code/addons/test/template/stories/unhandled-errors.stories.ts b/code/addons/test/template/stories/unhandled-errors.stories.ts index b9be0df743e0..d5c396b71683 100644 --- a/code/addons/test/template/stories/unhandled-errors.stories.ts +++ b/code/addons/test/template/stories/unhandled-errors.stories.ts @@ -1,5 +1,6 @@ import { global as globalThis } from '@storybook/global'; -import { userEvent, within } from '@storybook/test'; + +import { userEvent, within } from 'storybook/test'; export default { component: globalThis.Components.Button, diff --git a/code/addons/viewport/template/stories/parameters.stories.ts b/code/addons/viewport/template/stories/parameters.stories.ts index 697f675c214a..4ee419895aee 100644 --- a/code/addons/viewport/template/stories/parameters.stories.ts +++ b/code/addons/viewport/template/stories/parameters.stories.ts @@ -1,8 +1,9 @@ import { global as globalThis } from '@storybook/global'; -import { expect } from '@storybook/test'; import { MINIMAL_VIEWPORTS } from '@storybook/addon-viewport'; +import { expect } from 'storybook/test'; + // these stories only work with `viewportStoryGlobals` set to false // because the `default` prop is dropped and because, `values` changed to `options` and is now an object diff --git a/code/builders/builder-webpack5/src/index.ts b/code/builders/builder-webpack5/src/index.ts index b820f9e3c27e..34dd4f1a6f5f 100644 --- a/code/builders/builder-webpack5/src/index.ts +++ b/code/builders/builder-webpack5/src/index.ts @@ -29,7 +29,7 @@ export const printDuration = (startTime: [number, number]) => prettyTime(process.hrtime(startTime)) .replace(' ms', ' milliseconds') .replace(' s', ' seconds') - .replace(' m', ' minutes'); + .replace(' min', ' minutes'); const corePath = dirname(require.resolve('storybook/package.json')); diff --git a/code/core/package.json b/code/core/package.json index 8a0800475b73..02f8bcf78238 100644 --- a/code/core/package.json +++ b/code/core/package.json @@ -21,6 +21,12 @@ "license": "MIT", "sideEffects": false, "type": "module", + "imports": { + "#utils": { + "storybook": "./template/stories/utils.mock.ts", + "default": "./template/stories/utils.ts" + } + }, "exports": { ".": { "types": "./dist/index.d.ts", @@ -181,6 +187,11 @@ "import": "./dist/instrumenter/index.js", "require": "./dist/instrumenter/index.cjs" }, + "./test": { + "types": "./dist/test/index.d.ts", + "import": "./dist/test/index.js", + "require": "./dist/test/index.cjs" + }, "./internal/preview/runtime": { "import": "./dist/preview/runtime.js" }, @@ -280,6 +291,9 @@ ], "internal/instrumenter": [ "./dist/instrumenter/index.d.ts" + ], + "test": [ + "./dist/test/index.d.ts" ] } }, @@ -295,6 +309,11 @@ "prep": "jiti ./scripts/prep.ts" }, "dependencies": { + "@testing-library/dom": "10.4.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/user-event": "14.5.2", + "@vitest/expect": "2.0.5", + "@vitest/spy": "2.0.5", "better-opn": "^3.0.2", "browser-assert": "^1.2.1", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0", @@ -358,7 +377,9 @@ "babel-plugin-react-docgen": "4.2.1", "boxen": "^7.1.1", "browser-dtector": "^3.4.0", + "bundle-require": "^5.1.0", "camelcase": "^8.0.0", + "chai": "^5.1.1", "cli-table3": "^0.6.1", "commander": "^12.1.0", "comment-parser": "^1.4.1", @@ -423,7 +444,7 @@ "strip-json-comments": "^5.0.1", "telejson": "^7.2.0", "tiny-invariant": "^1.3.1", - "tinyspy": "^2.2.0", + "tinyspy": "^3.0.2", "ts-dedent": "^2.0.0", "tsconfig-paths": "^4.2.0", "type-fest": "^4.18.1", diff --git a/code/core/scripts/entries.ts b/code/core/scripts/entries.ts index 40396913186d..00357cf4601b 100644 --- a/code/core/scripts/entries.ts +++ b/code/core/scripts/entries.ts @@ -50,6 +50,23 @@ export const getEntries = (cwd: string) => { define('src/bin/index.ts', ['node'], false), define('src/instrumenter/index.ts', ['browser', 'node'], true), + define( + 'src/test/index.ts', + ['browser', 'node'], + true, + ['util'], + [], + [ + '@testing-library/dom', + '@testing-library/jest-dom', + '@testing-library/user-event', + 'chai', + '@vitest/expect', + '@vitest/spy', + '@vitest/utils', + ], + true + ), ]; }; diff --git a/code/core/scripts/helpers/generatePackageJsonFile.ts b/code/core/scripts/helpers/generatePackageJsonFile.ts index 020724b8113e..c5a0632e5a28 100644 --- a/code/core/scripts/helpers/generatePackageJsonFile.ts +++ b/code/core/scripts/helpers/generatePackageJsonFile.ts @@ -40,7 +40,7 @@ export async function generatePackageJsonFile(entries: ReturnType { function removeDefault(input: string) { diff --git a/code/core/scripts/no-externals-plugin.ts b/code/core/scripts/no-externals-plugin.ts new file mode 100644 index 000000000000..f2cb2abf9bbe --- /dev/null +++ b/code/core/scripts/no-externals-plugin.ts @@ -0,0 +1,21 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { match } from 'bundle-require'; +import type { Plugin } from 'esbuild'; + +// Must not start with "/" or "./" or "../" or "C:\" or be the exact strings ".." or "." +const NON_NODE_MODULE_RE = /^[A-Z]:[/\\]|^\.{0,2}\/|^\.{1,2}$/; + +export const externalPlugin = ({ noExternal }: { noExternal?: (string | RegExp)[] }): Plugin => { + return { + name: `external`, + + setup(build) { + build.onResolve({ filter: /.*/ }, (args) => { + // Respect explicit external/noExternal conditions + if (match(args.path, noExternal)) { + return undefined; + } + }); + }, + }; +}; diff --git a/code/core/scripts/prep.ts b/code/core/scripts/prep.ts index 2e431c57ceb3..16d18c1c7c72 100644 --- a/code/core/scripts/prep.ts +++ b/code/core/scripts/prep.ts @@ -25,6 +25,7 @@ import { generateTypesMapperFiles } from './helpers/generateTypesMapperFiles'; import { isBrowser, isNode, noExternals } from './helpers/isEntryType'; import { modifyThemeTypes } from './helpers/modifyThemeTypes'; import { generateSourceFiles } from './helpers/sourcefiles'; +import { externalPlugin } from './no-externals-plugin'; async function run() { const flags = process.argv.slice(2); @@ -253,9 +254,14 @@ async function run() { entryPoints: [entry.file], external: [ ...nodeInternals, - ...esbuildDefaultOptions.external, + ...esbuildDefaultOptions.external.filter((e) => !entry.noExternal.includes(e)), ...entry.externals, ].filter((e) => !entry.internals.includes(e)), + plugins: [ + externalPlugin({ + noExternal: entry.noExternal, + }), + ], format: 'cjs', outdir: dirname(entry.file).replace('src', 'dist'), outExtension: { @@ -272,10 +278,15 @@ async function run() { entryPoints: [entry.file], external: [ ...nodeInternals, - ...esbuildDefaultOptions.external, + ...esbuildDefaultOptions.external.filter((e) => !entry.noExternal.includes(e)), ...entry.externals, ].filter((e) => !entry.internals.includes(e)), outdir: dirname(entry.file).replace('src', 'dist'), + plugins: [ + externalPlugin({ + noExternal: entry.noExternal, + }), + ], outExtension: { '.js': '.js', }, @@ -289,9 +300,14 @@ async function run() { entryPoints: [entry.file], external: [ ...nodeInternals, - ...esbuildDefaultOptions.external, + ...esbuildDefaultOptions.external.filter((e) => !entry.noExternal.includes(e)), ...entry.externals, ].filter((e) => !entry.internals.includes(e)), + plugins: [ + externalPlugin({ + noExternal: entry.noExternal, + }), + ], format: 'esm', outdir: dirname(entry.file).replace('src', 'dist'), outExtension: { diff --git a/code/core/src/cli/helpers.test.ts b/code/core/src/cli/helpers.test.ts index a82dfc911a71..f161f4469ca7 100644 --- a/code/core/src/cli/helpers.test.ts +++ b/code/core/src/cli/helpers.test.ts @@ -158,7 +158,7 @@ describe('Helpers', () => { filePath === normalizePath('@storybook/react/template/cli') ); await helpers.copyTemplateFiles({ - renderer: 'react', + templateLocation: 'react', language, packageManager: packageManagerMock, commonAssetsDir: normalizePath('create-storybook/rendererAssets/common'), @@ -182,7 +182,7 @@ describe('Helpers', () => { return filePath === normalizePath('@storybook/react/template/cli') || filePath === './src'; }); await helpers.copyTemplateFiles({ - renderer: 'react', + templateLocation: 'react', language: SupportedLanguage.JAVASCRIPT, packageManager: packageManagerMock, features: ['dev', 'docs', 'test'], @@ -195,7 +195,7 @@ describe('Helpers', () => { return filePath === normalizePath('@storybook/react/template/cli'); }); await helpers.copyTemplateFiles({ - renderer: 'react', + templateLocation: 'react', language: SupportedLanguage.JAVASCRIPT, packageManager: packageManagerMock, features: ['dev', 'docs', 'test'], @@ -208,7 +208,7 @@ describe('Helpers', () => { const expectedMessage = `Unsupported renderer: ${renderer}`; await expect( helpers.copyTemplateFiles({ - renderer, + templateLocation: renderer, language: SupportedLanguage.JAVASCRIPT, packageManager: packageManagerMock, features: ['dev', 'docs', 'test'], diff --git a/code/core/src/cli/helpers.ts b/code/core/src/cli/helpers.ts index faee828be65d..9bab59fdd852 100644 --- a/code/core/src/cli/helpers.ts +++ b/code/core/src/cli/helpers.ts @@ -135,7 +135,7 @@ export function copyTemplate(templateRoot: string, destination = '.') { type CopyTemplateFilesOptions = { packageManager: JsPackageManager; - renderer: SupportedFrameworks | SupportedRenderers; + templateLocation: SupportedFrameworks | SupportedRenderers; language: SupportedLanguage; commonAssetsDir?: string; destination?: string; @@ -205,7 +205,7 @@ export const cliStoriesTargetPath = async () => { export async function copyTemplateFiles({ packageManager, - renderer, + templateLocation, language, destination, commonAssetsDir, @@ -218,7 +218,7 @@ export async function copyTemplateFiles({ [SupportedLanguage.TYPESCRIPT_4_9]: 'ts-4-9', }; // FIXME: remove after 9.0 - if (renderer === 'svelte') { + if (templateLocation === 'svelte') { const svelteVersion = await getVersionSafe(packageManager, 'svelte'); if (svelteVersion && major(svelteVersion) >= 5) { languageFolderMapping = { @@ -230,7 +230,7 @@ export async function copyTemplateFiles({ } } const templatePath = async () => { - const baseDir = await getRendererDir(packageManager, renderer); + const baseDir = await getRendererDir(packageManager, templateLocation); const assetsDir = join(baseDir, 'template', 'cli'); const assetsLanguage = join(assetsDir, languageFolderMapping[language]); @@ -253,7 +253,7 @@ export async function copyTemplateFiles({ if (existsSync(assetsDir)) { return assetsDir; } - throw new Error(`Unsupported renderer: ${renderer} (${baseDir})`); + throw new Error(`Unsupported renderer: ${templateLocation} (${baseDir})`); }; const destinationPath = destination ?? (await cliStoriesTargetPath()); @@ -264,7 +264,7 @@ export async function copyTemplateFiles({ await cp(await templatePath(), destinationPath, { recursive: true, filter }); if (commonAssetsDir && features.includes('docs')) { - let rendererType = frameworkToRenderer[renderer] || 'react'; + let rendererType = frameworkToRenderer[templateLocation] || 'react'; // This is only used for docs links and the docs site uses `vue` for both `vue` & `vue3` renderers if (rendererType === 'vue3') { diff --git a/code/core/src/common/js-package-manager/JsPackageManager.test.ts b/code/core/src/common/js-package-manager/JsPackageManager.test.ts index 153edd0be596..3ccdd59b0843 100644 --- a/code/core/src/common/js-package-manager/JsPackageManager.test.ts +++ b/code/core/src/common/js-package-manager/JsPackageManager.test.ts @@ -43,12 +43,12 @@ describe('JsPackageManager', () => { expect(result).toEqual(['@storybook/react@8.3.0']); }); - it('should return the latest stable release version when there is no current version', async () => { + it('should get the requested version when the package is not in the monorepo', async () => { mockLatestVersion.mockResolvedValue('2.0.0'); - const result = await jsPackageManager.getVersionedPackages(['@storybook/new-addon@^8.3.0']); + const result = await jsPackageManager.getVersionedPackages(['@storybook/new-addon@^next']); - expect(result).toEqual(['@storybook/new-addon@^2.0.0']); + expect(result).toEqual(['@storybook/new-addon@^next']); }); }); }); diff --git a/code/core/src/common/js-package-manager/JsPackageManager.ts b/code/core/src/common/js-package-manager/JsPackageManager.ts index 3d3ecfacfa20..a63a8efcc551 100644 --- a/code/core/src/common/js-package-manager/JsPackageManager.ts +++ b/code/core/src/common/js-package-manager/JsPackageManager.ts @@ -333,6 +333,13 @@ export abstract class JsPackageManager { return Promise.all( packages.map(async (pkg) => { const [packageName, packageVersion] = getPackageDetails(pkg); + + // If the packageVersion is specified and we are not dealing with a storybook package, + // just return the requested version. + if (packageVersion && !(packageName in storybookPackagesVersions)) { + return pkg; + } + const latestInRange = await this.latestVersion(packageName, packageVersion); const k = packageName as keyof typeof storybookPackagesVersions; diff --git a/code/core/src/common/utils/print-duration.ts b/code/core/src/common/utils/print-duration.ts index b7bcad0c6295..5a1f70f01516 100644 --- a/code/core/src/common/utils/print-duration.ts +++ b/code/core/src/common/utils/print-duration.ts @@ -4,4 +4,4 @@ export const printDuration = (startTime: [number, number]) => prettyTime(process.hrtime(startTime)) .replace(' ms', ' milliseconds') .replace(' s', ' seconds') - .replace(' m', ' minutes'); + .replace(' min', ' minutes'); diff --git a/code/core/src/common/versions.ts b/code/core/src/common/versions.ts index 0a12cf7b2e44..dad63691e839 100644 --- a/code/core/src/common/versions.ts +++ b/code/core/src/common/versions.ts @@ -50,7 +50,6 @@ export default { '@storybook/csf-plugin': '9.0.0-alpha.2', '@storybook/react-dom-shim': '9.0.0-alpha.2', '@storybook/source-loader': '9.0.0-alpha.2', - '@storybook/test': '9.0.0-alpha.2', '@storybook/preset-create-react-app': '9.0.0-alpha.2', '@storybook/preset-html-webpack': '9.0.0-alpha.2', '@storybook/preset-preact-webpack': '9.0.0-alpha.2', diff --git a/code/core/src/components/components/Badge/Badge.stories.tsx b/code/core/src/components/components/Badge/Badge.stories.tsx index 4f51422c0f0e..189f98bcebe8 100644 --- a/code/core/src/components/components/Badge/Badge.stories.tsx +++ b/code/core/src/components/components/Badge/Badge.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Badge } from './Badge'; diff --git a/code/core/src/components/components/Button/Button.deprecated.stories.tsx b/code/core/src/components/components/Button/Button.deprecated.stories.tsx index ee10af77e39b..fe7ebd265cc4 100644 --- a/code/core/src/components/components/Button/Button.deprecated.stories.tsx +++ b/code/core/src/components/components/Button/Button.deprecated.stories.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { LinkIcon } from '@storybook/icons'; -import type { Meta, StoryObj } from '@storybook/react'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Form } from '../form'; import { Button } from './Button'; diff --git a/code/core/src/components/components/ErrorFormatter/ErrorFormatter.stories.tsx b/code/core/src/components/components/ErrorFormatter/ErrorFormatter.stories.tsx index 3ffc4e68381d..e0f97d77c8c0 100644 --- a/code/core/src/components/components/ErrorFormatter/ErrorFormatter.stories.tsx +++ b/code/core/src/components/components/ErrorFormatter/ErrorFormatter.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { dedent } from 'ts-dedent'; diff --git a/code/core/src/components/components/IconButton/IconButton.stories.tsx b/code/core/src/components/components/IconButton/IconButton.stories.tsx index b7c8584cc150..b30009355b15 100644 --- a/code/core/src/components/components/IconButton/IconButton.stories.tsx +++ b/code/core/src/components/components/IconButton/IconButton.stories.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { FaceHappyIcon } from '@storybook/icons'; -import type { Meta, StoryObj } from '@storybook/react'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; import { IconButton } from './IconButton'; diff --git a/code/core/src/components/components/Modal/Modal.stories.tsx b/code/core/src/components/components/Modal/Modal.stories.tsx index 998e033d312e..71008f982878 100644 --- a/code/core/src/components/components/Modal/Modal.stories.tsx +++ b/code/core/src/components/components/Modal/Modal.stories.tsx @@ -1,7 +1,8 @@ import React, { useState } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, userEvent, within } from 'storybook/test'; import { Button } from '../Button/Button'; import { Modal } from './Modal'; diff --git a/code/core/src/components/components/ProgressSpinner/ProgressSpinner.stories.tsx b/code/core/src/components/components/ProgressSpinner/ProgressSpinner.stories.tsx index b0f03752bede..95724e3aa6dd 100644 --- a/code/core/src/components/components/ProgressSpinner/ProgressSpinner.stories.tsx +++ b/code/core/src/components/components/ProgressSpinner/ProgressSpinner.stories.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { StopAltIcon } from '@storybook/icons'; -import type { Meta, StoryObj } from '@storybook/react'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; import { ProgressSpinner } from './ProgressSpinner'; diff --git a/code/core/src/components/components/syntaxhighlighter/syntaxhighlighter.stories.tsx b/code/core/src/components/components/syntaxhighlighter/syntaxhighlighter.stories.tsx index 25367395b9c7..0996291bf5c7 100644 --- a/code/core/src/components/components/syntaxhighlighter/syntaxhighlighter.stories.tsx +++ b/code/core/src/components/components/syntaxhighlighter/syntaxhighlighter.stories.tsx @@ -180,7 +180,7 @@ export const UnsupportedDark = { export const Story = { args: { language: 'jsx', - children: `import type { Meta, StoryObj } from '@storybook/react'; + children: `import type { Meta, StoryObj } from '@storybook/react-vite'; import { Header } from './Header'; diff --git a/code/core/src/components/components/tabs/EmptyTabContent.stories.tsx b/code/core/src/components/components/tabs/EmptyTabContent.stories.tsx index fa4b90e709c4..313607e8e6b5 100644 --- a/code/core/src/components/components/tabs/EmptyTabContent.stories.tsx +++ b/code/core/src/components/components/tabs/EmptyTabContent.stories.tsx @@ -3,7 +3,8 @@ import React from 'react'; import { Link } from 'storybook/internal/components'; import { DocumentIcon } from '@storybook/icons'; -import type { Meta, StoryObj } from '@storybook/react'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; import { EmptyTabContent } from './EmptyTabContent'; diff --git a/code/core/src/components/components/tabs/tabs.stories.tsx b/code/core/src/components/components/tabs/tabs.stories.tsx index f70565a21029..e9e9fb72c684 100644 --- a/code/core/src/components/components/tabs/tabs.stories.tsx +++ b/code/core/src/components/components/tabs/tabs.stories.tsx @@ -1,12 +1,14 @@ import React from 'react'; import { BottomBarIcon, CloseIcon } from '@storybook/icons'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect } from '@storybook/test'; -import { findByText, fireEvent, screen, userEvent, waitFor, within } from '@storybook/test'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; +import { expect } from 'storybook/test'; +import { findByText, fireEvent, screen, userEvent, waitFor, within } from 'storybook/test'; + import { IconButton } from '../IconButton/IconButton'; import { TabWrapper, Tabs, TabsState } from './tabs'; import type { ChildrenList } from './tabs.helpers'; diff --git a/code/core/src/components/components/tooltip/TooltipLinkList.stories.tsx b/code/core/src/components/components/tooltip/TooltipLinkList.stories.tsx index 07e5ed7fc8d3..3ada84596100 100644 --- a/code/core/src/components/components/tooltip/TooltipLinkList.stories.tsx +++ b/code/core/src/components/components/tooltip/TooltipLinkList.stories.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { LinkIcon, LinuxIcon } from '@storybook/icons'; -import type { Meta, StoryObj } from '@storybook/react'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; diff --git a/code/core/src/components/components/tooltip/TooltipMessage.stories.tsx b/code/core/src/components/components/tooltip/TooltipMessage.stories.tsx index c84eb4dcc401..d55d5247d9cd 100644 --- a/code/core/src/components/components/tooltip/TooltipMessage.stories.tsx +++ b/code/core/src/components/components/tooltip/TooltipMessage.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta } from '@storybook/react'; +import type { Meta } from '@storybook/react-vite'; import { TooltipMessage } from './TooltipMessage'; import { WithTooltip } from './WithTooltip'; diff --git a/code/core/src/components/components/tooltip/WithTooltip.stories.tsx b/code/core/src/components/components/tooltip/WithTooltip.stories.tsx index 952dceeaf510..dc959ca07f1e 100644 --- a/code/core/src/components/components/tooltip/WithTooltip.stories.tsx +++ b/code/core/src/components/components/tooltip/WithTooltip.stories.tsx @@ -3,8 +3,9 @@ import React from 'react'; import { styled } from 'storybook/internal/theming'; -import type { StoryObj } from '@storybook/react'; -import { expect, screen } from '@storybook/test'; +import type { StoryObj } from '@storybook/react-vite'; + +import { expect, screen } from 'storybook/test'; import { TooltipMessage } from './TooltipMessage'; import { WithToolTipState as WithTooltip } from './WithTooltip'; diff --git a/code/core/src/core-server/utils/save-story/mocks/csf-variances.stories.tsx b/code/core/src/core-server/utils/save-story/mocks/csf-variances.stories.tsx index 674605e2ac4e..bc388c166473 100644 --- a/code/core/src/core-server/utils/save-story/mocks/csf-variances.stories.tsx +++ b/code/core/src/core-server/utils/save-story/mocks/csf-variances.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { FC } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; export default { title: 'MyComponent', diff --git a/code/core/src/core-server/utils/save-story/mocks/data-variances.stories.tsx b/code/core/src/core-server/utils/save-story/mocks/data-variances.stories.tsx index e049efd5339f..f75b6675ddfa 100644 --- a/code/core/src/core-server/utils/save-story/mocks/data-variances.stories.tsx +++ b/code/core/src/core-server/utils/save-story/mocks/data-variances.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { FC } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; export default { title: 'MyComponent', diff --git a/code/core/src/core-server/utils/save-story/mocks/export-variances.stories.tsx b/code/core/src/core-server/utils/save-story/mocks/export-variances.stories.tsx index 3fc94bcceaab..b0f0c86b6116 100644 --- a/code/core/src/core-server/utils/save-story/mocks/export-variances.stories.tsx +++ b/code/core/src/core-server/utils/save-story/mocks/export-variances.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { FC } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; export default { title: 'MyComponent', diff --git a/code/core/src/core-server/utils/save-story/mocks/typescript-constructs.stories.tsx b/code/core/src/core-server/utils/save-story/mocks/typescript-constructs.stories.tsx index 0d4aa951ad89..8e99617dcbbe 100644 --- a/code/core/src/core-server/utils/save-story/mocks/typescript-constructs.stories.tsx +++ b/code/core/src/core-server/utils/save-story/mocks/typescript-constructs.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { FC } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; export default { title: 'MyComponent', diff --git a/code/core/src/core-server/utils/save-story/mocks/unsupported-csf-variances.stories.tsx b/code/core/src/core-server/utils/save-story/mocks/unsupported-csf-variances.stories.tsx index 7a300959e0a8..05b0b8fd9002 100644 --- a/code/core/src/core-server/utils/save-story/mocks/unsupported-csf-variances.stories.tsx +++ b/code/core/src/core-server/utils/save-story/mocks/unsupported-csf-variances.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { FC } from 'react'; -import type { Meta } from '@storybook/react'; +import type { Meta } from '@storybook/react-vite'; export default { title: 'MyComponent', diff --git a/code/core/src/core-server/utils/warnWhenUsingArgTypesRegex.ts b/code/core/src/core-server/utils/warnWhenUsingArgTypesRegex.ts index 87d5d601dcd8..740720e49d9c 100644 --- a/code/core/src/core-server/utils/warnWhenUsingArgTypesRegex.ts +++ b/code/core/src/core-server/utils/warnWhenUsingArgTypesRegex.ts @@ -43,7 +43,7 @@ export async function warnWhenUsingArgTypesRegex( 'argTypesRegex' )} and assigning explicit action with the ${picocolors.cyan( 'fn' - )} function from ${picocolors.cyan('@storybook/test')} instead: + )} function from ${picocolors.cyan('storybook/test')} instead: https://storybook.js.org/docs/essentials/actions#via-storybooktest-fn-spy-function The build used by the addon for snapshot testing doesn't take the regex into account, which can cause hard to debug problems when a snapshot depends on the presence of action props. diff --git a/code/core/src/instrumenter/README.md b/code/core/src/instrumenter/README.md index 9f0227e0c913..058fe0e944bb 100644 --- a/code/core/src/instrumenter/README.md +++ b/code/core/src/instrumenter/README.md @@ -31,7 +31,7 @@ Depending on the library and functions to be instrumented, you may want to confi `intercept` can take either a boolean (default `false`) or a function which returns a boolean. This enables you to only make specific library functions interceptable. This function receives a `method` and `path`, referring to the name of the function and the path to that function in the object tree. Some functions may return an object which is then instrumented as well, in which case the `path` will contain a "call ref", which is a plain object containing a `__callId__` property referencing the originating call. -Here's an example `intercept` function (from `@storybook/test`): +Here's an example `intercept` function (from `storybook/test`): ```js (method, path) => path[0] === 'fireEvent' || method.startsWith('findBy') || method.startsWith('waitFor'), diff --git a/code/core/src/manager/components/layout/Layout.stories.tsx b/code/core/src/manager/components/layout/Layout.stories.tsx index e3f19df412db..df183c4ea0d4 100644 --- a/code/core/src/manager/components/layout/Layout.stories.tsx +++ b/code/core/src/manager/components/layout/Layout.stories.tsx @@ -4,11 +4,12 @@ import React, { useState } from 'react'; import { LocationProvider } from 'storybook/internal/router'; import { styled } from 'storybook/internal/theming'; -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; +import { fn } from 'storybook/test'; + import MobileNavigationStoriesMeta from '../mobile/navigation/MobileNavigation.stories'; import { Layout } from './Layout'; import { LayoutProvider } from './LayoutProvider'; diff --git a/code/core/src/manager/components/mobile/about/MobileAbout.stories.tsx b/code/core/src/manager/components/mobile/about/MobileAbout.stories.tsx index 36759e03950e..40ffe2555804 100644 --- a/code/core/src/manager/components/mobile/about/MobileAbout.stories.tsx +++ b/code/core/src/manager/components/mobile/about/MobileAbout.stories.tsx @@ -2,8 +2,9 @@ import React, { useEffect } from 'react'; import { ManagerContext } from 'storybook/internal/manager-api'; -import type { Meta, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { within } from 'storybook/test'; import { LayoutProvider, useLayout } from '../../layout/LayoutProvider'; import { MobileAbout } from './MobileAbout'; diff --git a/code/core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx b/code/core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx index 3ee9be594fc7..26913cee363c 100644 --- a/code/core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx +++ b/code/core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx @@ -2,10 +2,10 @@ import React from 'react'; import { ManagerContext } from 'storybook/internal/manager-api'; -import type { Meta, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { startCase } from 'es-toolkit'; +import { within } from 'storybook/test'; import { LayoutProvider, useLayout } from '../../layout/LayoutProvider'; import { MobileNavigation } from './MobileNavigation'; diff --git a/code/core/src/manager/components/notifications/NotificationItem.stories.tsx b/code/core/src/manager/components/notifications/NotificationItem.stories.tsx index 3af2381d945b..ee0c1fd09991 100644 --- a/code/core/src/manager/components/notifications/NotificationItem.stories.tsx +++ b/code/core/src/manager/components/notifications/NotificationItem.stories.tsx @@ -7,11 +7,13 @@ import { BookIcon as BookIconIcon, FaceHappyIcon, } from '@storybook/icons'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fn, userEvent, waitFor, within } from '@storybook/test'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; +import { expect, fn, userEvent, waitFor, within } from 'storybook/test'; + import NotificationItem from './NotificationItem'; const meta = { diff --git a/code/core/src/manager/components/notifications/NotificationList.stories.tsx b/code/core/src/manager/components/notifications/NotificationList.stories.tsx index d79faa6da1fa..7eecc760ba17 100644 --- a/code/core/src/manager/components/notifications/NotificationList.stories.tsx +++ b/code/core/src/manager/components/notifications/NotificationList.stories.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { LocationProvider } from 'storybook/internal/router'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import * as itemStories from './NotificationItem.stories'; import { NotificationList } from './NotificationList'; diff --git a/code/core/src/manager/components/sidebar/FileSearchList.stories.tsx b/code/core/src/manager/components/sidebar/FileSearchList.stories.tsx index 7388bf3cb4ab..e7c983aadef6 100644 --- a/code/core/src/manager/components/sidebar/FileSearchList.stories.tsx +++ b/code/core/src/manager/components/sidebar/FileSearchList.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, findByText, fireEvent, fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, findByText, fireEvent, fn } from 'storybook/test'; import { FileSearchList } from './FileSearchList'; diff --git a/code/core/src/manager/components/sidebar/FileSearchListSkeleton.stories.tsx b/code/core/src/manager/components/sidebar/FileSearchListSkeleton.stories.tsx index d8d38eeb6881..f7e4e436e339 100644 --- a/code/core/src/manager/components/sidebar/FileSearchListSkeleton.stories.tsx +++ b/code/core/src/manager/components/sidebar/FileSearchListSkeleton.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { FileSearchListLoadingSkeleton } from './FileSearchListSkeleton'; diff --git a/code/core/src/manager/components/sidebar/FileSearchModal.stories.tsx b/code/core/src/manager/components/sidebar/FileSearchModal.stories.tsx index c9e1790ef118..ef6a8ecf9786 100644 --- a/code/core/src/manager/components/sidebar/FileSearchModal.stories.tsx +++ b/code/core/src/manager/components/sidebar/FileSearchModal.stories.tsx @@ -1,7 +1,8 @@ import React, { useState } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, findByText, fireEvent, fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, findByText, fireEvent, fn } from 'storybook/test'; import { WithResults } from './FileSearchList.stories'; import { FileSearchModal } from './FileSearchModal'; diff --git a/code/core/src/manager/components/sidebar/FilterToggle.stories.ts b/code/core/src/manager/components/sidebar/FilterToggle.stories.ts index 075b8c94dc9a..f7528c87afee 100644 --- a/code/core/src/manager/components/sidebar/FilterToggle.stories.ts +++ b/code/core/src/manager/components/sidebar/FilterToggle.stories.ts @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { FilterToggle } from './FilterToggle'; diff --git a/code/core/src/manager/components/sidebar/Heading.stories.tsx b/code/core/src/manager/components/sidebar/Heading.stories.tsx index 8e12d3eb7778..208a62e4469e 100644 --- a/code/core/src/manager/components/sidebar/Heading.stories.tsx +++ b/code/core/src/manager/components/sidebar/Heading.stories.tsx @@ -4,11 +4,12 @@ import React from 'react'; import { ThemeProvider, useTheme } from 'storybook/internal/theming'; import type { Theme } from 'storybook/internal/theming'; -import type { Meta, StoryFn, StoryObj } from '@storybook/react'; -import { screen } from '@storybook/test'; +import type { Meta, StoryFn, StoryObj } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; +import { screen } from 'storybook/test'; + import { Heading } from './Heading'; type Story = StoryFn; diff --git a/code/core/src/manager/components/sidebar/IconSymbols.stories.tsx b/code/core/src/manager/components/sidebar/IconSymbols.stories.tsx index 143c08932d37..39f05e6e0055 100644 --- a/code/core/src/manager/components/sidebar/IconSymbols.stories.tsx +++ b/code/core/src/manager/components/sidebar/IconSymbols.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { IconSymbols } from './IconSymbols'; diff --git a/code/core/src/manager/components/sidebar/Menu.stories.tsx b/code/core/src/manager/components/sidebar/Menu.stories.tsx index 858a04a2be98..fb5f34170b47 100644 --- a/code/core/src/manager/components/sidebar/Menu.stories.tsx +++ b/code/core/src/manager/components/sidebar/Menu.stories.tsx @@ -5,8 +5,10 @@ import type { State } from 'storybook/internal/manager-api'; import { styled } from 'storybook/internal/theming'; import { LinkIcon } from '@storybook/icons'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, screen, userEvent, within } from '@storybook/test'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, screen, userEvent, within } from 'storybook/test'; import { useMenu } from '../../container/Menu'; import { LayoutProvider } from '../layout/LayoutProvider'; diff --git a/code/core/src/manager/components/sidebar/Refs.stories.tsx b/code/core/src/manager/components/sidebar/Refs.stories.tsx index c137c252e116..7dd746e41230 100644 --- a/code/core/src/manager/components/sidebar/Refs.stories.tsx +++ b/code/core/src/manager/components/sidebar/Refs.stories.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { ManagerContext } from 'storybook/internal/manager-api'; -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { standardData as standardHeaderData } from './Heading.stories'; import { IconSymbols } from './IconSymbols'; diff --git a/code/core/src/manager/components/sidebar/Search.stories.tsx b/code/core/src/manager/components/sidebar/Search.stories.tsx index 09a34d80dc8b..0d83f2f1ad63 100644 --- a/code/core/src/manager/components/sidebar/Search.stories.tsx +++ b/code/core/src/manager/components/sidebar/Search.stories.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { API } from 'storybook/internal/manager-api'; import { ManagerContext } from 'storybook/internal/manager-api'; -import type { Meta, StoryFn } from '@storybook/react'; +import type { Meta, StoryFn } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; diff --git a/code/core/src/manager/components/sidebar/Sidebar.stories.tsx b/code/core/src/manager/components/sidebar/Sidebar.stories.tsx index 973419fccc74..505e011cfc06 100644 --- a/code/core/src/manager/components/sidebar/Sidebar.stories.tsx +++ b/code/core/src/manager/components/sidebar/Sidebar.stories.tsx @@ -4,8 +4,9 @@ import type { IndexHash, State } from 'storybook/internal/manager-api'; import { ManagerContext } from 'storybook/internal/manager-api'; import type { API_StatusState, Addon_SidebarTopType } from 'storybook/internal/types'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fn, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, fn, userEvent, within } from 'storybook/test'; import { LayoutProvider } from '../layout/LayoutProvider'; import { standardData as standardHeaderData } from './Heading.stories'; diff --git a/code/core/src/manager/components/sidebar/SidebarBottom.stories.tsx b/code/core/src/manager/components/sidebar/SidebarBottom.stories.tsx index 9d7fd7d8392b..93805bbc4f35 100644 --- a/code/core/src/manager/components/sidebar/SidebarBottom.stories.tsx +++ b/code/core/src/manager/components/sidebar/SidebarBottom.stories.tsx @@ -3,8 +3,9 @@ import React, { type FC, useEffect, useState } from 'react'; import { type API, ManagerContext } from 'storybook/internal/manager-api'; import { Addon_TypesEnum } from 'storybook/internal/types'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fireEvent, fn, waitFor, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, fireEvent, fn, waitFor, within } from 'storybook/test'; import { SidebarBottomBase } from './SidebarBottom'; diff --git a/code/core/src/manager/components/sidebar/TagsFilter.stories.tsx b/code/core/src/manager/components/sidebar/TagsFilter.stories.tsx index 89236acda68a..d7be4feedc38 100644 --- a/code/core/src/manager/components/sidebar/TagsFilter.stories.tsx +++ b/code/core/src/manager/components/sidebar/TagsFilter.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { findByRole, fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { findByRole, fn } from 'storybook/test'; import { TagsFilter } from './TagsFilter'; diff --git a/code/core/src/manager/components/sidebar/TagsFilterPanel.stories.tsx b/code/core/src/manager/components/sidebar/TagsFilterPanel.stories.tsx index 0602d0ed7a43..7884b231d309 100644 --- a/code/core/src/manager/components/sidebar/TagsFilterPanel.stories.tsx +++ b/code/core/src/manager/components/sidebar/TagsFilterPanel.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { TagsFilterPanel } from './TagsFilterPanel'; diff --git a/code/core/src/manager/components/sidebar/TestingModule.stories.tsx b/code/core/src/manager/components/sidebar/TestingModule.stories.tsx index b043c006b4c0..a6a515c3d136 100644 --- a/code/core/src/manager/components/sidebar/TestingModule.stories.tsx +++ b/code/core/src/manager/components/sidebar/TestingModule.stories.tsx @@ -6,8 +6,9 @@ import { ManagerContext, mockChannel } from 'storybook/internal/manager-api'; import { styled } from 'storybook/internal/theming'; import { Addon_TypesEnum } from 'storybook/internal/types'; -import type { Meta, StoryObj } from '@storybook/react'; -import { fireEvent, fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fireEvent, fn } from 'storybook/test'; import { TestingModule } from './TestingModule'; diff --git a/code/core/src/manager/components/sidebar/Tree.stories.tsx b/code/core/src/manager/components/sidebar/Tree.stories.tsx index fdc231ba94fd..40ead720cdfc 100644 --- a/code/core/src/manager/components/sidebar/Tree.stories.tsx +++ b/code/core/src/manager/components/sidebar/Tree.stories.tsx @@ -7,11 +7,12 @@ import { ManagerContext, } from 'storybook/internal/manager-api'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fn, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; +import { expect, fn, userEvent, within } from 'storybook/test'; + import { DEFAULT_REF_ID } from './Sidebar'; import { Tree } from './Tree'; import { index } from './mockdata.large'; diff --git a/code/core/src/manager/components/upgrade/UpgradeBlock.stories.tsx b/code/core/src/manager/components/upgrade/UpgradeBlock.stories.tsx index e882a41bf180..b3c3fdae32d3 100644 --- a/code/core/src/manager/components/upgrade/UpgradeBlock.stories.tsx +++ b/code/core/src/manager/components/upgrade/UpgradeBlock.stories.tsx @@ -2,8 +2,9 @@ import React from 'react'; import { ManagerContext } from 'storybook/internal/manager-api'; -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { UpgradeBlock } from './UpgradeBlock'; diff --git a/code/core/src/manager/container/Menu.stories.tsx b/code/core/src/manager/container/Menu.stories.tsx index c2633bb73df7..1ba78e1652e0 100644 --- a/code/core/src/manager/container/Menu.stories.tsx +++ b/code/core/src/manager/container/Menu.stories.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { TooltipLinkList, WithTooltip } from 'storybook/internal/components'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; diff --git a/code/core/src/manager/settings/SettingsFooter.stories.tsx b/code/core/src/manager/settings/SettingsFooter.stories.tsx index fb138e96b689..12b4af50f425 100644 --- a/code/core/src/manager/settings/SettingsFooter.stories.tsx +++ b/code/core/src/manager/settings/SettingsFooter.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Decorator } from '@storybook/react'; +import type { Decorator } from '@storybook/react-vite'; import SettingsFooter from './SettingsFooter'; diff --git a/code/core/src/manager/settings/about.stories.tsx b/code/core/src/manager/settings/about.stories.tsx index d63d246d447a..a89d90078bde 100644 --- a/code/core/src/manager/settings/about.stories.tsx +++ b/code/core/src/manager/settings/about.stories.tsx @@ -1,7 +1,8 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import UpgradeBlockStoriesMeta from '../components/upgrade/UpgradeBlock.stories'; import { AboutScreen } from './About'; diff --git a/code/core/src/manager/settings/shortcuts.stories.tsx b/code/core/src/manager/settings/shortcuts.stories.tsx index 67f3b97a149d..b58bc38e11e9 100644 --- a/code/core/src/manager/settings/shortcuts.stories.tsx +++ b/code/core/src/manager/settings/shortcuts.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Decorator } from '@storybook/react'; +import type { Decorator } from '@storybook/react-vite'; import { actions as makeActions } from '@storybook/addon-actions'; diff --git a/code/core/src/manager/settings/whats_new_footer.stories.tsx b/code/core/src/manager/settings/whats_new_footer.stories.tsx index 9e0a88c04562..440bdf19919a 100644 --- a/code/core/src/manager/settings/whats_new_footer.stories.tsx +++ b/code/core/src/manager/settings/whats_new_footer.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { WhatsNewFooter } from './whats_new'; diff --git a/code/core/src/preview-errors.ts b/code/core/src/preview-errors.ts index eb083277daa8..bed6db57243c 100644 --- a/code/core/src/preview-errors.ts +++ b/code/core/src/preview-errors.ts @@ -60,7 +60,7 @@ export class ImplicitActionsDuringRendering extends StorybookError { We detected that you use an implicit action arg while ${data.phase} of your story. ${data.deprecated ? `\nThis is deprecated and won't work in Storybook 8 anymore.\n` : ``} Please provide an explicit spy to your args like this: - import { fn } from '@storybook/test'; + import { fn } from 'storybook/test'; ... args: { ${data.name}: fn() diff --git a/code/core/src/shared/universal-store/index.test.ts b/code/core/src/shared/universal-store/index.test.ts index ced895809781..c589a79539f8 100644 --- a/code/core/src/shared/universal-store/index.test.ts +++ b/code/core/src/shared/universal-store/index.test.ts @@ -46,9 +46,12 @@ const mockChannel = { describe('UniversalStore', () => { beforeEach((context) => { vi.useFakeTimers(); - let randomUUIDCounter = 0; - vi.spyOn(globalThis.crypto, 'randomUUID').mockImplementation(() => { - return `mocked-random-uuid-v4-${randomUUIDCounter++}`; + + // Mock Date and Math.random to make the actorId deterministic + let randomNumberCounter = 1; + vi.setSystemTime(new Date('2025-02-14')); + vi.spyOn(Math, 'random').mockImplementation(() => { + return randomNumberCounter++ / 10; }); // Always prepare the store, unless the test is specifically for unprepared state @@ -57,7 +60,7 @@ describe('UniversalStore', () => { } return () => { - randomUUIDCounter = 0; + randomNumberCounter = 0; vi.clearAllTimers(); mockedInstances.clearAllEnvironments(); mockChannelListeners.clear(); @@ -78,7 +81,7 @@ describe('UniversalStore', () => { // Assert - the store should be created with the initial state and actor expect(store.getState()).toEqual({ count: 0 }); expect(store.actor.type).toBe('LEADER'); - expect(store.actor.id).toBe('mocked-random-uuid-v4-0'); + expect(store.actor.id).toBe('m7405c003lllllllllm'); }); it('should throw when trying to create an instance with the constructor directly', () => { @@ -195,7 +198,6 @@ You should reuse the existing instance instead of trying to create a new one.`); // Arrange - create an initial leader and follower vi.spyOn(console, 'error').mockImplementation(() => {}); - vi.spyOn(globalThis.crypto, 'randomUUID').mockReturnValueOnce('first-uuid-1-2-3-4'); const firstLeader = UniversalStore.create({ id: 'env1:test', leader: true, @@ -203,7 +205,6 @@ You should reuse the existing instance instead of trying to create a new one.`); }); // Act - create the second leader - vi.spyOn(globalThis.crypto, 'randomUUID').mockReturnValueOnce('second-uuid-1-2-3-4'); const secondLeader = UniversalStore.create({ id: 'env2:test', leader: true, @@ -250,12 +251,12 @@ You should reuse the existing instance instead of trying to create a new one.`); Only one leader can exists at a time, your stores are now in an invalid state. Leaders detected: this: { - "id": "second-uuid-1-2-3-4", + "id": "m7405c0077777777778", "type": "LEADER", "environment": "MANAGER" } other: { - "id": "first-uuid-1-2-3-4", + "id": "m7405c003lllllllllm", "type": "LEADER", "environment": "MANAGER" }` @@ -266,12 +267,12 @@ You should reuse the existing instance instead of trying to create a new one.`); Only one leader can exists at a time, your stores are now in an invalid state. Leaders detected: this: { - "id": "first-uuid-1-2-3-4", + "id": "m7405c003lllllllllm", "type": "LEADER", "environment": "MANAGER" } other: { - "id": "second-uuid-1-2-3-4", + "id": "m7405c0077777777778", "type": "LEADER", "environment": "MANAGER" }` @@ -290,7 +291,7 @@ You should reuse the existing instance instead of trying to create a new one.`); // Assert - the store should be created with the initial state and actor expect(store.getState()).toEqual(undefined); expect(store.actor.type).toBe('FOLLOWER'); - expect(store.actor.id).toBe('mocked-random-uuid-v4-0'); + expect(store.actor.id).toBe('m7405c003lllllllllm'); }); it('should get existing state when a follower is created without initialState', async () => { @@ -325,7 +326,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "LEADER", }, }, @@ -340,7 +341,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", }, }, @@ -355,7 +356,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", }, }, @@ -370,12 +371,12 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", }, "forwardingActor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "LEADER", }, }, @@ -393,7 +394,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "LEADER", }, }, @@ -437,7 +438,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "LEADER", }, }, @@ -452,7 +453,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", }, }, @@ -467,7 +468,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", }, }, @@ -482,12 +483,12 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", }, "forwardingActor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "LEADER", }, }, @@ -505,7 +506,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "LEADER", }, }, @@ -560,7 +561,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "LEADER", }, }, @@ -575,7 +576,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", }, }, @@ -590,7 +591,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", }, }, @@ -605,12 +606,12 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", }, "forwardingActor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "LEADER", }, }, @@ -628,7 +629,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "LEADER", }, }, @@ -664,7 +665,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "FOLLOWER", }, }, @@ -679,7 +680,7 @@ You should reuse the existing instance instead of trying to create a new one.`); "eventInfo": { "actor": { "environment": "MANAGER", - "id": "mocked-random-uuid-v4-0", + "id": "m7405c003lllllllllm", "type": "FOLLOWER", }, }, @@ -951,7 +952,7 @@ You should reuse the existing instance instead of trying to create a new one.`); }, "id": "env2:test", "actor": { - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", "environment": "MANAGER" }, @@ -1136,7 +1137,7 @@ You should reuse the existing instance instead of trying to create a new one.`); }, "id": "env2:test", "actor": { - "id": "mocked-random-uuid-v4-1", + "id": "m7405c0077777777778", "type": "FOLLOWER", "environment": "MANAGER" }, diff --git a/code/core/src/shared/universal-store/index.ts b/code/core/src/shared/universal-store/index.ts index 3e033c0c5e14..df94ca009c4a 100644 --- a/code/core/src/shared/universal-store/index.ts +++ b/code/core/src/shared/universal-store/index.ts @@ -259,10 +259,7 @@ export class UniversalStore< UniversalStore.isInternalConstructing = false; this.id = options.id; - this.actorId = globalThis.crypto - ? globalThis.crypto.randomUUID() - : // TODO: remove this fallback in SB 9.0 when we no longer support Node 18 - Date.now().toString(36) + Math.random().toString(36).substring(2); + this.actorId = Date.now().toString(36) + Math.random().toString(36).substring(2); this.actorType = options.leader ? UniversalStore.ActorType.LEADER : UniversalStore.ActorType.FOLLOWER; diff --git a/code/core/src/shared/universal-store/mock.ts b/code/core/src/shared/universal-store/mock.ts index a5695f48464b..fc7214300cec 100644 --- a/code/core/src/shared/universal-store/mock.ts +++ b/code/core/src/shared/universal-store/mock.ts @@ -21,7 +21,7 @@ import type { StoreOptions } from './types'; * @example * * ```ts - * import * as testUtils from '@storybook/test'; // in stories + * import * as testUtils from 'storybook/test'; // in stories * import { vi as testUtils } from 'vitest'; // ... or in Vitest tests * * const initialState = { ... }; diff --git a/code/lib/test/README.md b/code/core/src/test/README.md similarity index 67% rename from code/lib/test/README.md rename to code/core/src/test/README.md index 81efc0635b0b..a823cad323cf 100644 --- a/code/lib/test/README.md +++ b/code/core/src/test/README.md @@ -1,18 +1,6 @@ # Storybook Test -The `@storybook/test` package contains utilities for testing your stories inside `play` functions. - -## Installation - -Install the package by adding the `@storybook/test` dev dependency: - -```sh -npm install -D @storybook/test -pnpm add -D @storybook/test -yarn add -D @storybook/test -``` - -Note that this package is not an addon, so you don't have to add it to your `main.js/main.ts` file. +The `storybook/test` package contains utilities for testing your stories inside `play` functions. ## Usage @@ -21,7 +9,7 @@ The instrumentation makes sure you can debug those methods in the [addon-interac ```ts // Button.stories.ts -import { expect, fn, userEvent, within } from '@storybook/test'; +import { expect, fn, userEvent, within } from 'storybook/test'; import { Button } from './Button'; export default { diff --git a/code/lib/test/src/expect.ts b/code/core/src/test/expect.ts similarity index 100% rename from code/lib/test/src/expect.ts rename to code/core/src/test/expect.ts diff --git a/code/lib/test/src/index.test.ts b/code/core/src/test/index.test.ts similarity index 94% rename from code/lib/test/src/index.test.ts rename to code/core/src/test/index.test.ts index e87c485c991b..fb9fe2cd5aea 100644 --- a/code/lib/test/src/index.test.ts +++ b/code/core/src/test/index.test.ts @@ -1,10 +1,10 @@ // @vitest-environment happy-dom import { describe, it, test } from 'vitest'; -import { expect, fn, isMockFunction, traverseArgs } from '@storybook/test'; - import { action } from '@storybook/addon-actions'; +import { expect, fn, isMockFunction, traverseArgs } from 'storybook/test'; + it('storybook expect and fn can be used in vitest test', () => { const spy = fn(); spy(1); diff --git a/code/lib/test/src/index.ts b/code/core/src/test/index.ts similarity index 97% rename from code/lib/test/src/index.ts rename to code/core/src/test/index.ts index 54cfc8dbfa2a..6c5bba5c7028 100644 --- a/code/lib/test/src/index.ts +++ b/code/core/src/test/index.ts @@ -5,7 +5,7 @@ import { instrument } from 'storybook/internal/instrumenter'; import { global } from '@storybook/global'; -import * as chai from 'chai'; +import { Assertion } from 'chai'; import { expect as rawExpect } from './expect'; import { @@ -35,7 +35,7 @@ export const { expect } = instrument( { getKeys: (obj: Record, depth) => { const privateApi = ['assert', '__methods', '__flags', '_obj']; - if (obj.constructor === chai.Assertion) { + if (obj.constructor === Assertion) { const keys = Object.keys(Object.getPrototypeOf(obj)).filter( (it) => !privateApi.includes(it) ); diff --git a/code/lib/test/src/spy.test.ts b/code/core/src/test/spy.test.ts similarity index 100% rename from code/lib/test/src/spy.test.ts rename to code/core/src/test/spy.test.ts diff --git a/code/lib/test/src/spy.ts b/code/core/src/test/spy.ts similarity index 100% rename from code/lib/test/src/spy.ts rename to code/core/src/test/spy.ts diff --git a/code/lib/test/src/testing-library.ts b/code/core/src/test/testing-library.ts similarity index 97% rename from code/lib/test/src/testing-library.ts rename to code/core/src/test/testing-library.ts index c3f395640a30..a193904f8045 100644 --- a/code/lib/test/src/testing-library.ts +++ b/code/core/src/test/testing-library.ts @@ -116,6 +116,7 @@ type _UserEvent = typeof _userEvent; export interface UserEvent extends _UserEvent {} export const { userEvent }: { userEvent: UserEvent } = instrument( - { userEvent: _userEvent }, + // @ts-expect-error CJS workaround + { userEvent: _userEvent.default ?? _userEvent }, { intercept: true } ); diff --git a/code/lib/test/src/utils.ts b/code/core/src/test/utils.ts similarity index 100% rename from code/lib/test/src/utils.ts rename to code/core/src/test/utils.ts diff --git a/code/core/template/stories/argMapping.stories.ts b/code/core/template/stories/argMapping.stories.ts index f2813a95d26d..5b829b31ffac 100644 --- a/code/core/template/stories/argMapping.stories.ts +++ b/code/core/template/stories/argMapping.stories.ts @@ -1,7 +1,8 @@ import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; const arrows = { ArrowUp: { name: 'ArrowUp' }, diff --git a/code/core/template/stories/argTypes.stories.ts b/code/core/template/stories/argTypes.stories.ts index d64316c63b8e..c97a9ef289e6 100644 --- a/code/core/template/stories/argTypes.stories.ts +++ b/code/core/template/stories/argTypes.stories.ts @@ -1,7 +1,8 @@ import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/core/template/stories/args.stories.ts b/code/core/template/stories/args.stories.ts index 43eed8f50703..a3b7c3894752 100644 --- a/code/core/template/stories/args.stories.ts +++ b/code/core/template/stories/args.stories.ts @@ -6,7 +6,8 @@ import { import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; function pick(obj, keys) { const result = {}; diff --git a/code/core/template/stories/autotitle.stories.ts b/code/core/template/stories/autotitle.stories.ts index 9399cf241216..dea8cf850ad5 100644 --- a/code/core/template/stories/autotitle.stories.ts +++ b/code/core/template/stories/autotitle.stories.ts @@ -1,7 +1,8 @@ import type { PlayFunctionContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect } from '@storybook/test'; + +import { expect } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/lib/test/template/stories/before-each.stories.ts b/code/core/template/stories/before-each.stories.ts similarity index 96% rename from code/lib/test/template/stories/before-each.stories.ts rename to code/core/template/stories/before-each.stories.ts index 0d9a88cafa3c..5d23e6c8b125 100644 --- a/code/lib/test/template/stories/before-each.stories.ts +++ b/code/core/template/stories/before-each.stories.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention,storybook/prefer-pascal-case */ -import { expect } from '@storybook/test'; +import { expect } from 'storybook/test'; const meta = { component: globalThis.Components.Button, diff --git a/code/core/template/stories/component-play.stories.ts b/code/core/template/stories/component-play.stories.ts index db93783ed167..e71102fe50f0 100644 --- a/code/core/template/stories/component-play.stories.ts +++ b/code/core/template/stories/component-play.stories.ts @@ -1,7 +1,8 @@ import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/core/template/stories/decorators.stories.ts b/code/core/template/stories/decorators.stories.ts index d0822c0ab8c8..117bfdf8ce0a 100644 --- a/code/core/template/stories/decorators.stories.ts +++ b/code/core/template/stories/decorators.stories.ts @@ -12,7 +12,8 @@ import type { } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/lib/test/template/stories/destructuring-not-transpiled.stories.ts b/code/core/template/stories/destructuring-not-transpiled.stories.ts similarity index 94% rename from code/lib/test/template/stories/destructuring-not-transpiled.stories.ts rename to code/core/template/stories/destructuring-not-transpiled.stories.ts index b1f2c98e220e..be1b38051e86 100644 --- a/code/lib/test/template/stories/destructuring-not-transpiled.stories.ts +++ b/code/core/template/stories/destructuring-not-transpiled.stories.ts @@ -1,5 +1,6 @@ import { global as globalThis } from '@storybook/global'; -import { expect } from '@storybook/test'; + +import { expect } from 'storybook/test'; export default { component: globalThis.Components.Button, diff --git a/code/core/template/stories/globals.stories.ts b/code/core/template/stories/globals.stories.ts index cbede539ce79..cf6be5d0d1bc 100644 --- a/code/core/template/stories/globals.stories.ts +++ b/code/core/template/stories/globals.stories.ts @@ -1,7 +1,8 @@ import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/core/template/stories/hooks.stories.ts b/code/core/template/stories/hooks.stories.ts index b2d2cc01e73a..17704662b1bd 100644 --- a/code/core/template/stories/hooks.stories.ts +++ b/code/core/template/stories/hooks.stories.ts @@ -2,7 +2,8 @@ import { useEffect, useState } from 'storybook/internal/preview-api'; import type { PartialStoryFn, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { userEvent, within } from '@storybook/test'; + +import { userEvent, within } from 'storybook/test'; export default { component: globalThis.Components.Button, diff --git a/code/core/template/stories/indexer.stories.ts b/code/core/template/stories/indexer.stories.ts index 684b195e5bfd..1ec6ad17e5b7 100644 --- a/code/core/template/stories/indexer.stories.ts +++ b/code/core/template/stories/indexer.stories.ts @@ -1,7 +1,8 @@ import type { PlayFunctionContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect } from '@storybook/test'; + +import { expect } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/lib/test/template/stories/loader-enhancements.stories.ts b/code/core/template/stories/loader-enhancements.stories.ts similarity index 90% rename from code/lib/test/template/stories/loader-enhancements.stories.ts rename to code/core/template/stories/loader-enhancements.stories.ts index fdd1a7c4e646..07ac2d783b64 100644 --- a/code/lib/test/template/stories/loader-enhancements.stories.ts +++ b/code/core/template/stories/loader-enhancements.stories.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention,storybook/prefer-pascal-case */ -import { expect, userEvent as globalUserEvent, within } from '@storybook/test'; +import { expect, userEvent as globalUserEvent, within } from 'storybook/test'; const meta = { component: globalThis.Components.Button, diff --git a/code/core/template/stories/loaders.stories.ts b/code/core/template/stories/loaders.stories.ts index b9a5d31eaf18..ec035ca03d42 100644 --- a/code/core/template/stories/loaders.stories.ts +++ b/code/core/template/stories/loaders.stories.ts @@ -1,7 +1,8 @@ import type { PartialStoryFn, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/lib/test/template/stories/module-mocking.stories.ts b/code/core/template/stories/module-mocking.stories.ts similarity index 90% rename from code/lib/test/template/stories/module-mocking.stories.ts rename to code/core/template/stories/module-mocking.stories.ts index f773f675ff57..4afd1d526638 100644 --- a/code/lib/test/template/stories/module-mocking.stories.ts +++ b/code/core/template/stories/module-mocking.stories.ts @@ -1,9 +1,9 @@ import { global as globalThis } from '@storybook/global'; -import { expect, fn, isMockFunction, mocked } from '@storybook/test'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore This alias is set in the sandbox. Using ts-ignore instead of ts-expect-error to avoid build errors in the sandbox. import { foo } from '#utils'; +import { expect, fn, isMockFunction, mocked } from 'storybook/test'; export default { component: globalThis.Components.Button, diff --git a/code/lib/test/template/stories/mount-in-play.stories.ts b/code/core/template/stories/mount-in-play.stories.ts similarity index 92% rename from code/lib/test/template/stories/mount-in-play.stories.ts rename to code/core/template/stories/mount-in-play.stories.ts index 22c92497783d..795c0a2fd5aa 100644 --- a/code/lib/test/template/stories/mount-in-play.stories.ts +++ b/code/core/template/stories/mount-in-play.stories.ts @@ -1,4 +1,4 @@ -import { expect, fn } from '@storybook/test'; +import { expect, fn } from 'storybook/test'; const meta = { component: globalThis.Components.Button }; diff --git a/code/core/template/stories/names.stories.ts b/code/core/template/stories/names.stories.ts index 9ad9320b4e5b..14547843f345 100644 --- a/code/core/template/stories/names.stories.ts +++ b/code/core/template/stories/names.stories.ts @@ -1,7 +1,8 @@ import type { PlayFunctionContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect } from '@storybook/test'; + +import { expect } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/lib/test/template/stories/order-of-hooks.stories.ts b/code/core/template/stories/order-of-hooks.stories.ts similarity index 94% rename from code/lib/test/template/stories/order-of-hooks.stories.ts rename to code/core/template/stories/order-of-hooks.stories.ts index f3e965dee1b3..8306457cf14e 100644 --- a/code/lib/test/template/stories/order-of-hooks.stories.ts +++ b/code/core/template/stories/order-of-hooks.stories.ts @@ -1,4 +1,4 @@ -import { expect, fn, getByRole, mocked, spyOn, userEvent } from '@storybook/test'; +import { expect, getByRole, mocked, spyOn, userEvent } from 'storybook/test'; const meta = { component: globalThis.Components.Button, diff --git a/code/core/template/stories/parameters.stories.ts b/code/core/template/stories/parameters.stories.ts index 5d7020197197..d1582af593a1 100644 --- a/code/core/template/stories/parameters.stories.ts +++ b/code/core/template/stories/parameters.stories.ts @@ -1,7 +1,8 @@ import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/core/template/stories/rendering.stories.ts b/code/core/template/stories/rendering.stories.ts index 31cb903d19b5..4876376a9575 100644 --- a/code/core/template/stories/rendering.stories.ts +++ b/code/core/template/stories/rendering.stories.ts @@ -7,7 +7,8 @@ import { import type { PlayFunctionContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, waitFor, within } from '@storybook/test'; + +import { expect, waitFor, within } from 'storybook/test'; export default { component: globalThis.Components.Button, diff --git a/code/core/template/stories/shortcuts.stories.ts b/code/core/template/stories/shortcuts.stories.ts index 998b417d3de4..81bc3f5ae2a2 100644 --- a/code/core/template/stories/shortcuts.stories.ts +++ b/code/core/template/stories/shortcuts.stories.ts @@ -2,7 +2,8 @@ import { PREVIEW_KEYDOWN } from 'storybook/internal/core-events'; import type { PlayFunctionContext } from 'storybook/internal/csf'; import { global as globalThis } from '@storybook/global'; -import { expect, fn, userEvent, within } from '@storybook/test'; + +import { expect, fn, userEvent, within } from 'storybook/test'; export default { component: globalThis.Components.Form, diff --git a/code/core/template/stories/tags-add.stories.ts b/code/core/template/stories/tags-add.stories.ts index a86addb4aea6..078c4eb2beff 100644 --- a/code/core/template/stories/tags-add.stories.ts +++ b/code/core/template/stories/tags-add.stories.ts @@ -1,7 +1,8 @@ import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/core/template/stories/tags-config.stories.ts b/code/core/template/stories/tags-config.stories.ts index 03c835832e5c..04292ae8790f 100644 --- a/code/core/template/stories/tags-config.stories.ts +++ b/code/core/template/stories/tags-config.stories.ts @@ -1,7 +1,8 @@ import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/core/template/stories/tags-remove.stories.ts b/code/core/template/stories/tags-remove.stories.ts index 27c313381a73..133d836275c9 100644 --- a/code/core/template/stories/tags-remove.stories.ts +++ b/code/core/template/stories/tags-remove.stories.ts @@ -1,7 +1,8 @@ import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect, within } from '@storybook/test'; + +import { expect, within } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/core/template/stories/title.stories.ts b/code/core/template/stories/title.stories.ts index 0c0246a096f8..e5fed6c34fa9 100644 --- a/code/core/template/stories/title.stories.ts +++ b/code/core/template/stories/title.stories.ts @@ -1,7 +1,8 @@ import type { PlayFunctionContext } from 'storybook/internal/types'; import { global as globalThis } from '@storybook/global'; -import { expect } from '@storybook/test'; + +import { expect } from 'storybook/test'; export default { component: globalThis.Components.Pre, diff --git a/code/core/template/stories/utils.mock.ts b/code/core/template/stories/utils.mock.ts index 93a72d03a0e2..430f08797aec 100644 --- a/code/core/template/stories/utils.mock.ts +++ b/code/core/template/stories/utils.mock.ts @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import * as utils from './utils.ts'; diff --git a/code/e2e-tests/module-mocking.spec.ts b/code/e2e-tests/module-mocking.spec.ts index 3341f6449002..ae57661f1d8f 100644 --- a/code/e2e-tests/module-mocking.spec.ts +++ b/code/e2e-tests/module-mocking.spec.ts @@ -15,7 +15,7 @@ test.describe('module-mocking', () => { test('should assert story lifecycle order', async ({ page }) => { const sbPage = new SbPage(page, expect); - await sbPage.navigateToStory('lib/test/order-of-hooks', 'order-of-hooks'); + await sbPage.navigateToStory('core/order-of-hooks', 'order-of-hooks'); await sbPage.viewAddonPanel('Actions'); const logItem = page.locator('#storybook-panel-root #panel-tab-content'); @@ -43,7 +43,7 @@ test.describe('module-mocking', () => { test('should assert that utils import is mocked', async ({ page }) => { const sbPage = new SbPage(page, expect); - await sbPage.navigateToStory('lib/test/module-mocking', 'basic'); + await sbPage.navigateToStory('core/module-mocking', 'basic'); await sbPage.viewAddonPanel('Actions'); const logItem = page.locator('#storybook-panel-root #panel-tab-content', { diff --git a/code/frameworks/angular/template/cli/button.stories.ts b/code/frameworks/angular/template/cli/button.stories.ts index dedeca1f2e9b..5c12e3141883 100644 --- a/code/frameworks/angular/template/cli/button.stories.ts +++ b/code/frameworks/angular/template/cli/button.stories.ts @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/angular'; -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { ButtonComponent } from './button.component'; diff --git a/code/frameworks/angular/template/cli/header.stories.ts b/code/frameworks/angular/template/cli/header.stories.ts index ea9b0894e4b4..8a9f73b151c8 100644 --- a/code/frameworks/angular/template/cli/header.stories.ts +++ b/code/frameworks/angular/template/cli/header.stories.ts @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/angular'; -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { HeaderComponent } from './header.component'; diff --git a/code/frameworks/angular/template/cli/page.stories.ts b/code/frameworks/angular/template/cli/page.stories.ts index 8237ee228b34..47c99b233f79 100644 --- a/code/frameworks/angular/template/cli/page.stories.ts +++ b/code/frameworks/angular/template/cli/page.stories.ts @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/angular'; -import { expect, userEvent, within } from '@storybook/test'; +import { expect, userEvent, within } from 'storybook/test'; import { PageComponent } from './page.component'; diff --git a/code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.stories.ts b/code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.stories.ts index db1fa2125d53..6849fc9bb42a 100644 --- a/code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.stories.ts +++ b/code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj } from '@storybook/angular'; -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import SignalButtonComponent from './button.component'; diff --git a/code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.stories.ts b/code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.stories.ts index db1fa2125d53..6849fc9bb42a 100644 --- a/code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.stories.ts +++ b/code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj } from '@storybook/angular'; -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import SignalButtonComponent from './button.component'; diff --git a/code/frameworks/ember/template/cli/Button.stories.js b/code/frameworks/ember/template/cli/Button.stories.js index 35ba57166a77..93511eade468 100644 --- a/code/frameworks/ember/template/cli/Button.stories.js +++ b/code/frameworks/ember/template/cli/Button.stories.js @@ -1,9 +1,8 @@ -import { fn } from '@storybook/test'; - import { action } from '@storybook/addon-actions'; import { linkTo } from '@storybook/addon-links'; import { hbs } from 'ember-cli-htmlbars'; +import { fn } from 'storybook/test'; // More on how to set up stories at: https://storybook.js.org/docs/writing-stories export default { diff --git a/code/frameworks/experimental-nextjs-vite/package.json b/code/frameworks/experimental-nextjs-vite/package.json index a9f2f906c5d0..02cd4b01cb76 100644 --- a/code/frameworks/experimental-nextjs-vite/package.json +++ b/code/frameworks/experimental-nextjs-vite/package.json @@ -107,9 +107,8 @@ "@storybook/builder-vite": "workspace:*", "@storybook/react": "workspace:*", "@storybook/react-vite": "workspace:*", - "@storybook/test": "workspace:*", "styled-jsx": "5.1.6", - "vite-plugin-storybook-nextjs": "^1.1.0" + "vite-plugin-storybook-nextjs": "2.0.0--canary.33.a61ad85.0" }, "devDependencies": { "@types/node": "^22.0.0", @@ -117,7 +116,6 @@ "typescript": "^5.7.3" }, "peerDependencies": { - "@storybook/test": "workspace:*", "next": "^14.1.0 || ^15.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", @@ -129,9 +127,6 @@ "optional": true } }, - "optionalDependencies": { - "sharp": "^0.33.3" - }, "engines": { "node": ">=18.0.0" }, diff --git a/code/frameworks/experimental-nextjs-vite/src/export-mocks/cache/index.ts b/code/frameworks/experimental-nextjs-vite/src/export-mocks/cache/index.ts index 35b74b8cb02f..d81ed0affc73 100644 --- a/code/frameworks/experimental-nextjs-vite/src/export-mocks/cache/index.ts +++ b/code/frameworks/experimental-nextjs-vite/src/export-mocks/cache/index.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; // biome-ignore lint/suspicious/noExplicitAny: type Callback = (...args: any[]) => Promise; diff --git a/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/cookies.ts b/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/cookies.ts index b1eb6a692ef0..4697a1afb97a 100644 --- a/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/cookies.ts +++ b/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/cookies.ts @@ -1,13 +1,12 @@ // We need this import to be a singleton, and because it's used in multiple entrypoints // both in ESM and CJS, importing it via the package name instead of having a local import // is the only way to achieve it actually being a singleton -import { fn } from '@storybook/test'; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore we must ignore types here as during compilation they are not generated yet import { headers } from '@storybook/experimental-nextjs-vite/headers.mock'; import { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies'; +import { fn } from 'storybook/test'; class RequestCookiesMock extends RequestCookies { get = fn(super.get.bind(this)).mockName('next/headers::cookies().get'); diff --git a/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/headers.ts b/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/headers.ts index 1aceec57089c..1d65c9285d93 100644 --- a/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/headers.ts +++ b/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/headers.ts @@ -1,6 +1,5 @@ -import { fn } from '@storybook/test'; - import { HeadersAdapter } from 'next/dist/server/web/spec-extension/adapters/headers'; +import { fn } from 'storybook/test'; class HeadersAdapterMock extends HeadersAdapter { constructor() { diff --git a/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/index.ts b/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/index.ts index 1c903963ba2d..f1e27b49c646 100644 --- a/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/index.ts +++ b/code/frameworks/experimental-nextjs-vite/src/export-mocks/headers/index.ts @@ -1,7 +1,6 @@ -import { fn } from '@storybook/test'; - import { draftMode as originalDraftMode } from 'next/dist/server/request/draft-mode'; import * as headers from 'next/dist/server/request/headers'; +import { fn } from 'storybook/test'; // re-exports of the actual module export * from 'next/dist/server/request/headers'; diff --git a/code/frameworks/experimental-nextjs-vite/src/export-mocks/navigation/index.ts b/code/frameworks/experimental-nextjs-vite/src/export-mocks/navigation/index.ts index 8cec0b3266fb..c2c63c3c78dc 100644 --- a/code/frameworks/experimental-nextjs-vite/src/export-mocks/navigation/index.ts +++ b/code/frameworks/experimental-nextjs-vite/src/export-mocks/navigation/index.ts @@ -1,11 +1,10 @@ import { NextjsRouterMocksNotAvailable } from 'storybook/internal/preview-errors'; -import type { Mock } from '@storybook/test'; -import { fn } from '@storybook/test'; - import * as actual from 'next/dist/client/components/navigation'; import { getRedirectError } from 'next/dist/client/components/redirect'; import { RedirectStatusCode } from 'next/dist/client/components/redirect-status-code'; +import type { Mock } from 'storybook/test'; +import { fn } from 'storybook/test'; let navigationAPI: { push: Mock; diff --git a/code/frameworks/experimental-nextjs-vite/src/export-mocks/router/index.ts b/code/frameworks/experimental-nextjs-vite/src/export-mocks/router/index.ts index c6e93e804f0f..26ee30342c70 100644 --- a/code/frameworks/experimental-nextjs-vite/src/export-mocks/router/index.ts +++ b/code/frameworks/experimental-nextjs-vite/src/export-mocks/router/index.ts @@ -1,10 +1,9 @@ import { NextjsRouterMocksNotAvailable } from 'storybook/internal/preview-errors'; -import type { Mock } from '@storybook/test'; -import { fn } from '@storybook/test'; - import singletonRouter, * as originalRouter from 'next/dist/client/router'; import type { NextRouter, SingletonRouter } from 'next/router'; +import type { Mock } from 'storybook/test'; +import { fn } from 'storybook/test'; const defaultRouterState = { route: '/', diff --git a/code/frameworks/experimental-nextjs-vite/src/index.ts b/code/frameworks/experimental-nextjs-vite/src/index.ts index a7ab6e7ede7c..ed2829032a7e 100644 --- a/code/frameworks/experimental-nextjs-vite/src/index.ts +++ b/code/frameworks/experimental-nextjs-vite/src/index.ts @@ -1,12 +1,17 @@ +import type { ProjectAnnotations } from 'storybook/internal/types'; + import type { ReactPreview } from '@storybook/react'; import { __definePreview } from '@storybook/react'; +import type { ReactRenderer } from '@storybook/react'; import type vitePluginStorybookNextJs from 'vite-plugin-storybook-nextjs'; import * as nextPreview from './preview'; -export * from './types'; +export * from '@storybook/react'; +// @ts-expect-error (double exports) export * from './portable-stories'; +export * from './types'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -17,7 +22,10 @@ declare module '@storybook/experimental-nextjs-vite/vite-plugin' { export function definePreview(preview: NextPreview['input']) { return __definePreview({ ...preview, - addons: [nextPreview, ...(preview.addons ?? [])], + addons: [ + nextPreview as unknown as ProjectAnnotations, + ...(preview.addons ?? []), + ], }) as NextPreview; } diff --git a/code/frameworks/experimental-nextjs-vite/src/preview.tsx b/code/frameworks/experimental-nextjs-vite/src/preview.tsx index 57804c4e13b6..86d6629f3854 100644 --- a/code/frameworks/experimental-nextjs-vite/src/preview.tsx +++ b/code/frameworks/experimental-nextjs-vite/src/preview.tsx @@ -1,4 +1,8 @@ -import type { Addon_DecoratorFunction, Addon_LoaderFunction } from 'storybook/internal/types'; +import type * as React from 'react'; + +import type { Addon_DecoratorFunction, LoaderFunction } from 'storybook/internal/types'; + +import type { ReactRenderer, StoryFn } from '@storybook/react'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore we must ignore types here as during compilation they are not generated yet @@ -50,21 +54,25 @@ globalThis.addEventListener('error', (ev: WindowEventMap['error']): void => { } }); -export const decorators: Addon_DecoratorFunction[] = [ - StyledJsxDecorator, - ImageDecorator, - RouterDecorator, - HeadManagerDecorator, +// Type assertion to handle the decorator type mismatch +const asDecorator = (decorator: (Story: React.FC, context?: any) => React.ReactNode) => + decorator as unknown as Addon_DecoratorFunction; + +export const decorators: Addon_DecoratorFunction[] = [ + asDecorator(StyledJsxDecorator), + asDecorator(ImageDecorator), + asDecorator(RouterDecorator), + asDecorator(HeadManagerDecorator), ]; -export const loaders: Addon_LoaderFunction = async ({ globals, parameters }) => { +export const loaders: LoaderFunction = async ({ globals, parameters }) => { const { router, appDirectory } = parameters.nextjs ?? {}; if (appDirectory) { createNavigation(router); } else { createRouter({ locale: globals.locale, - ...router, + ...(router as Record), }); } }; diff --git a/code/frameworks/experimental-nextjs-vite/template/cli/js/Button.stories.js b/code/frameworks/experimental-nextjs-vite/template/cli/js/Button.stories.js index 045d9c477ab1..1b56021e71d9 100644 --- a/code/frameworks/experimental-nextjs-vite/template/cli/js/Button.stories.js +++ b/code/frameworks/experimental-nextjs-vite/template/cli/js/Button.stories.js @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/frameworks/experimental-nextjs-vite/template/cli/js/Header.stories.js b/code/frameworks/experimental-nextjs-vite/template/cli/js/Header.stories.js index 699abab07946..9fe689e0ac82 100644 --- a/code/frameworks/experimental-nextjs-vite/template/cli/js/Header.stories.js +++ b/code/frameworks/experimental-nextjs-vite/template/cli/js/Header.stories.js @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { Header } from './Header'; diff --git a/code/frameworks/experimental-nextjs-vite/template/cli/js/Page.stories.js b/code/frameworks/experimental-nextjs-vite/template/cli/js/Page.stories.js index 7b9906a73514..1ffea36cf374 100644 --- a/code/frameworks/experimental-nextjs-vite/template/cli/js/Page.stories.js +++ b/code/frameworks/experimental-nextjs-vite/template/cli/js/Page.stories.js @@ -1,4 +1,4 @@ -import { expect, userEvent, within } from '@storybook/test'; +import { expect, userEvent, within } from 'storybook/test'; import { Page } from './Page'; diff --git a/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Button.stories.ts index 2a05e01b06fe..6a6779580f97 100644 --- a/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Button.stories.ts +++ b/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Button.stories.ts @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; + +import { fn } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Header.stories.ts b/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Header.stories.ts index 80c71d0f520e..3e99df690033 100644 --- a/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Header.stories.ts +++ b/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Header.stories.ts @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; + +import { fn } from 'storybook/test'; import { Header } from './Header'; diff --git a/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Page.stories.ts b/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Page.stories.ts index 5d2c688a978f..fcdcca745800 100644 --- a/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Page.stories.ts +++ b/code/frameworks/experimental-nextjs-vite/template/cli/ts-4-9/Page.stories.ts @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; + +import { expect, userEvent, within } from 'storybook/test'; import { Page } from './Page'; diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/DynamicImport.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/DynamicImport.stories.tsx index f6b5e2c99f3b..ecc6eddfbba5 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/DynamicImport.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/DynamicImport.stories.tsx @@ -1,6 +1,6 @@ import React, { Suspense } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import dynamic from 'next/dynamic'; diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/Font.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/Font.stories.tsx index 32db81dcb67d..2287970d6046 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/Font.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/Font.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import Font from './Font'; diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/GetImageProps.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/GetImageProps.stories.tsx index d4ad15ab240f..f23e61872c47 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/GetImageProps.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/GetImageProps.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import { type ImageProps, getImageProps } from 'next/image'; diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/Head.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/Head.stories.tsx index 0d344078868f..3ba0228887fd 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/Head.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/Head.stories.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import type { Meta } from '@storybook/react'; -import type { StoryObj } from '@storybook/react'; -import { expect, waitFor } from '@storybook/test'; +import type { Meta } from '@storybook/experimental-nextjs-vite'; +import type { StoryObj } from '@storybook/experimental-nextjs-vite'; import Head from 'next/head'; +import { expect, waitFor } from 'storybook/test'; function Component() { return ( diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/Image.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/Image.stories.tsx index d9efdacdae80..1c9e1235c144 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/Image.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/Image.stories.tsx @@ -1,6 +1,6 @@ import React, { useRef, useState } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import Image from 'next/image'; diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/ImageLegacy.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/ImageLegacy.stories.tsx index 5e8852c2fb38..00752e97ced8 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/ImageLegacy.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/ImageLegacy.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import Image from 'next/legacy/image'; diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/Link.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/Link.stories.tsx index d071539c57a5..ae599692733d 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/Link.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/Link.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import Link from 'next/link'; diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/Navigation.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/Navigation.stories.tsx index 4b9b49904de0..92f07126ee0d 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/Navigation.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/Navigation.stories.tsx @@ -1,8 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; - +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import { getRouter } from '@storybook/experimental-nextjs-vite/navigation.mock'; import { @@ -13,6 +11,7 @@ import { useSelectedLayoutSegment, useSelectedLayoutSegments, } from 'next/navigation'; +import { expect, userEvent, within } from 'storybook/test'; function Component() { const router = useRouter(); diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/NextHeader.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/NextHeader.stories.tsx index 1d31006f63e7..d6b464df5c1b 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/NextHeader.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/NextHeader.stories.tsx @@ -1,9 +1,9 @@ -import type { Meta } from '@storybook/react'; -import type { StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; - +import type { Meta } from '@storybook/experimental-nextjs-vite'; +import type { StoryObj } from '@storybook/experimental-nextjs-vite'; import { cookies, headers } from '@storybook/experimental-nextjs-vite/headers.mock'; +import { expect, userEvent, within } from 'storybook/test'; + import NextHeader from './NextHeader'; export default { diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/RSC.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/RSC.stories.tsx index 655a5f1a93e4..1045bc8c6042 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/RSC.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/RSC.stories.tsx @@ -1,7 +1,7 @@ /* eslint-disable local-rules/no-uncategorized-errors */ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import { Nested, RSC } from './RSC'; diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/Redirect.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/Redirect.stories.tsx index 47fd4c5228d1..0bf00616405c 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/Redirect.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/Redirect.stories.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import { redirect } from 'next/navigation'; +import { userEvent, within } from 'storybook/test'; let state = 'Bug! Not invalidated'; diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/Router.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/Router.stories.tsx index 7b1d5b0ec0c9..402c3c945de9 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/Router.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/Router.stories.tsx @@ -1,11 +1,10 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; - +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import { getRouter } from '@storybook/experimental-nextjs-vite/router.mock'; import Router, { useRouter } from 'next/router'; +import { expect, userEvent, within } from 'storybook/test'; function Component() { const router = useRouter(); diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/ServerActions.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/ServerActions.stories.tsx index 0844293c34f3..c813aaa9f28c 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/ServerActions.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/ServerActions.stories.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, waitFor, within } from '@storybook/test'; - +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; import { revalidatePath } from '@storybook/experimental-nextjs-vite/cache.mock'; import { cookies } from '@storybook/experimental-nextjs-vite/headers.mock'; import { getRouter, redirect } from '@storybook/experimental-nextjs-vite/navigation.mock'; +import { expect, userEvent, waitFor, within } from 'storybook/test'; + import { accessRoute, login, logout } from './ServerActions'; function Component() { diff --git a/code/frameworks/experimental-nextjs-vite/template/stories/StyledJsx.stories.tsx b/code/frameworks/experimental-nextjs-vite/template/stories/StyledJsx.stories.tsx index 31adea42456c..64c9f9b5b4f4 100644 --- a/code/frameworks/experimental-nextjs-vite/template/stories/StyledJsx.stories.tsx +++ b/code/frameworks/experimental-nextjs-vite/template/stories/StyledJsx.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/experimental-nextjs-vite'; const Component = () => (
diff --git a/code/frameworks/html-vite/src/index.ts b/code/frameworks/html-vite/src/index.ts index fcb073fefcd6..a5fd712c4ce5 100644 --- a/code/frameworks/html-vite/src/index.ts +++ b/code/frameworks/html-vite/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/html'; export * from './types'; diff --git a/code/frameworks/html-webpack5/src/index.ts b/code/frameworks/html-webpack5/src/index.ts index fcb073fefcd6..a5fd712c4ce5 100644 --- a/code/frameworks/html-webpack5/src/index.ts +++ b/code/frameworks/html-webpack5/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/html'; export * from './types'; diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index ebe47d1b8ba7..1192820ad4d8 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -156,12 +156,11 @@ "@storybook/builder-webpack5": "workspace:*", "@storybook/preset-react-webpack": "workspace:*", "@storybook/react": "workspace:*", - "@storybook/test": "workspace:*", "@types/semver": "^7.3.4", "babel-loader": "^9.1.3", "css-loader": "^6.7.3", "find-up": "^5.0.0", - "image-size": "^1.0.0", + "image-size": "^2.0.0", "loader-utils": "^3.2.1", "node-polyfill-webpack-plugin": "^2.0.1", "pnp-webpack-plugin": "^1.7.0", @@ -204,9 +203,6 @@ "optional": true } }, - "optionalDependencies": { - "sharp": "^0.33.3" - }, "engines": { "node": ">=18.0.0" }, diff --git a/code/frameworks/nextjs/src/export-mocks/cache/index.ts b/code/frameworks/nextjs/src/export-mocks/cache/index.ts index 0344304bc795..16ecd0b42e4a 100644 --- a/code/frameworks/nextjs/src/export-mocks/cache/index.ts +++ b/code/frameworks/nextjs/src/export-mocks/cache/index.ts @@ -1,7 +1,6 @@ -import { fn } from '@storybook/test'; - import { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'; import { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store'; +import { fn } from 'storybook/test'; // mock utilities/overrides (as of Next v14.2.0) const revalidatePath = fn().mockName('next/cache::revalidatePath'); diff --git a/code/frameworks/nextjs/src/export-mocks/headers/cookies.ts b/code/frameworks/nextjs/src/export-mocks/headers/cookies.ts index 02e335834b8a..b8125b5fef1c 100644 --- a/code/frameworks/nextjs/src/export-mocks/headers/cookies.ts +++ b/code/frameworks/nextjs/src/export-mocks/headers/cookies.ts @@ -4,9 +4,9 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore we must ignore types here as during compilation they are not generated yet import { headers } from '@storybook/nextjs/headers.mock'; -import { fn } from '@storybook/test'; import { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies'; +import { fn } from 'storybook/test'; class RequestCookiesMock extends RequestCookies { get = fn(super.get.bind(this)).mockName('next/headers::cookies().get'); diff --git a/code/frameworks/nextjs/src/export-mocks/headers/headers.ts b/code/frameworks/nextjs/src/export-mocks/headers/headers.ts index 1aceec57089c..1d65c9285d93 100644 --- a/code/frameworks/nextjs/src/export-mocks/headers/headers.ts +++ b/code/frameworks/nextjs/src/export-mocks/headers/headers.ts @@ -1,6 +1,5 @@ -import { fn } from '@storybook/test'; - import { HeadersAdapter } from 'next/dist/server/web/spec-extension/adapters/headers'; +import { fn } from 'storybook/test'; class HeadersAdapterMock extends HeadersAdapter { constructor() { diff --git a/code/frameworks/nextjs/src/export-mocks/headers/index.ts b/code/frameworks/nextjs/src/export-mocks/headers/index.ts index 1c903963ba2d..f1e27b49c646 100644 --- a/code/frameworks/nextjs/src/export-mocks/headers/index.ts +++ b/code/frameworks/nextjs/src/export-mocks/headers/index.ts @@ -1,7 +1,6 @@ -import { fn } from '@storybook/test'; - import { draftMode as originalDraftMode } from 'next/dist/server/request/draft-mode'; import * as headers from 'next/dist/server/request/headers'; +import { fn } from 'storybook/test'; // re-exports of the actual module export * from 'next/dist/server/request/headers'; diff --git a/code/frameworks/nextjs/src/export-mocks/navigation/index.ts b/code/frameworks/nextjs/src/export-mocks/navigation/index.ts index 8cec0b3266fb..c2c63c3c78dc 100644 --- a/code/frameworks/nextjs/src/export-mocks/navigation/index.ts +++ b/code/frameworks/nextjs/src/export-mocks/navigation/index.ts @@ -1,11 +1,10 @@ import { NextjsRouterMocksNotAvailable } from 'storybook/internal/preview-errors'; -import type { Mock } from '@storybook/test'; -import { fn } from '@storybook/test'; - import * as actual from 'next/dist/client/components/navigation'; import { getRedirectError } from 'next/dist/client/components/redirect'; import { RedirectStatusCode } from 'next/dist/client/components/redirect-status-code'; +import type { Mock } from 'storybook/test'; +import { fn } from 'storybook/test'; let navigationAPI: { push: Mock; diff --git a/code/frameworks/nextjs/src/export-mocks/router/index.ts b/code/frameworks/nextjs/src/export-mocks/router/index.ts index c6e93e804f0f..26ee30342c70 100644 --- a/code/frameworks/nextjs/src/export-mocks/router/index.ts +++ b/code/frameworks/nextjs/src/export-mocks/router/index.ts @@ -1,10 +1,9 @@ import { NextjsRouterMocksNotAvailable } from 'storybook/internal/preview-errors'; -import type { Mock } from '@storybook/test'; -import { fn } from '@storybook/test'; - import singletonRouter, * as originalRouter from 'next/dist/client/router'; import type { NextRouter, SingletonRouter } from 'next/router'; +import type { Mock } from 'storybook/test'; +import { fn } from 'storybook/test'; const defaultRouterState = { route: '/', diff --git a/code/frameworks/nextjs/src/index.ts b/code/frameworks/nextjs/src/index.ts index 92aebbe57d31..f91791742e5b 100644 --- a/code/frameworks/nextjs/src/index.ts +++ b/code/frameworks/nextjs/src/index.ts @@ -3,7 +3,9 @@ import { __definePreview } from '@storybook/react'; import * as nextPreview from './preview'; +export * from '@storybook/react'; export * from './types'; +// @ts-expect-error (double exports) export * from './portable-stories'; export function definePreview(preview: NextPreview['input']) { diff --git a/code/frameworks/nextjs/src/next-image-loader-stub.ts b/code/frameworks/nextjs/src/next-image-loader-stub.ts index e85414c85d15..a562c2764738 100644 --- a/code/frameworks/nextjs/src/next-image-loader-stub.ts +++ b/code/frameworks/nextjs/src/next-image-loader-stub.ts @@ -1,8 +1,4 @@ -import { cpus } from 'node:os'; - -import { NextJsSharpError } from 'storybook/internal/preview-errors'; - -import imageSizeOf from 'image-size'; +import { imageSize } from 'image-size'; import { interpolateName } from 'loader-utils'; import type { NextConfig } from 'next'; import type { RawLoaderDefinition } from 'webpack'; @@ -12,21 +8,6 @@ interface LoaderOptions { nextConfig: NextConfig; } -let sharp: typeof import('sharp') | undefined; - -try { - sharp = require('sharp'); - if (sharp && sharp.concurrency() > 1) { - // Reducing concurrency reduces the memory usage too. - const divisor = process.env.NODE_ENV === 'development' ? 4 : 2; - sharp.concurrency(Math.floor(Math.max(cpus().length / divisor, 1))); - } -} catch (e) { - console.warn( - 'You have to install sharp in order to use image optimization features in Next.js. AVIF support is also disabled.' - ); -} - const nextImageLoaderStub: RawLoaderDefinition = async function NextImageLoader( content ) { @@ -36,7 +17,6 @@ const nextImageLoaderStub: RawLoaderDefinition = async function N content, }; const outputPath = interpolateName(this, filename.replace('[ext]', '.[ext]'), opts); - const extension = interpolateName(this, '[ext]', opts); this.emitFile(outputPath, content); @@ -44,23 +24,7 @@ const nextImageLoaderStub: RawLoaderDefinition = async function N return `const src = '${outputPath}'; export default src;`; } - let width; - let height; - - if (extension === 'avif') { - if (sharp) { - const transformer = sharp(content); - const result = await transformer.metadata(); - width = result.width; - height = result.height; - } else { - throw new NextJsSharpError(); - } - } else { - const result = imageSizeOf(this.resourcePath); - width = result.width; - height = result.height; - } + const { width, height } = imageSize(content as Uint8Array); return `export default ${JSON.stringify({ src: outputPath, diff --git a/code/frameworks/nextjs/template/cli/js/Button.stories.js b/code/frameworks/nextjs/template/cli/js/Button.stories.js index 045d9c477ab1..1b56021e71d9 100644 --- a/code/frameworks/nextjs/template/cli/js/Button.stories.js +++ b/code/frameworks/nextjs/template/cli/js/Button.stories.js @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/frameworks/nextjs/template/cli/js/Header.stories.js b/code/frameworks/nextjs/template/cli/js/Header.stories.js index 699abab07946..9fe689e0ac82 100644 --- a/code/frameworks/nextjs/template/cli/js/Header.stories.js +++ b/code/frameworks/nextjs/template/cli/js/Header.stories.js @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { Header } from './Header'; diff --git a/code/frameworks/nextjs/template/cli/js/Page.stories.js b/code/frameworks/nextjs/template/cli/js/Page.stories.js index 7b9906a73514..1ffea36cf374 100644 --- a/code/frameworks/nextjs/template/cli/js/Page.stories.js +++ b/code/frameworks/nextjs/template/cli/js/Page.stories.js @@ -1,4 +1,4 @@ -import { expect, userEvent, within } from '@storybook/test'; +import { expect, userEvent, within } from 'storybook/test'; import { Page } from './Page'; diff --git a/code/frameworks/nextjs/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/nextjs/template/cli/ts-4-9/Button.stories.ts index 2a05e01b06fe..747e7c8b3e62 100644 --- a/code/frameworks/nextjs/template/cli/ts-4-9/Button.stories.ts +++ b/code/frameworks/nextjs/template/cli/ts-4-9/Button.stories.ts @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/nextjs'; + +import { fn } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/frameworks/nextjs/template/cli/ts-4-9/Header.stories.ts b/code/frameworks/nextjs/template/cli/ts-4-9/Header.stories.ts index 80c71d0f520e..56ed5e07cfdd 100644 --- a/code/frameworks/nextjs/template/cli/ts-4-9/Header.stories.ts +++ b/code/frameworks/nextjs/template/cli/ts-4-9/Header.stories.ts @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/nextjs'; + +import { fn } from 'storybook/test'; import { Header } from './Header'; diff --git a/code/frameworks/nextjs/template/cli/ts-4-9/Page.stories.ts b/code/frameworks/nextjs/template/cli/ts-4-9/Page.stories.ts index 5d2c688a978f..97f11551f56a 100644 --- a/code/frameworks/nextjs/template/cli/ts-4-9/Page.stories.ts +++ b/code/frameworks/nextjs/template/cli/ts-4-9/Page.stories.ts @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/nextjs'; + +import { expect, userEvent, within } from 'storybook/test'; import { Page } from './Page'; diff --git a/code/frameworks/nextjs/template/stories/DynamicImport.stories.tsx b/code/frameworks/nextjs/template/stories/DynamicImport.stories.tsx index b71430f72544..b33f6bb449f0 100644 --- a/code/frameworks/nextjs/template/stories/DynamicImport.stories.tsx +++ b/code/frameworks/nextjs/template/stories/DynamicImport.stories.tsx @@ -1,6 +1,6 @@ import React, { Suspense } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import dynamic from 'next/dynamic'; diff --git a/code/frameworks/nextjs/template/stories/Font.stories.tsx b/code/frameworks/nextjs/template/stories/Font.stories.tsx index 0e078409da0b..c7b5eb69220d 100644 --- a/code/frameworks/nextjs/template/stories/Font.stories.tsx +++ b/code/frameworks/nextjs/template/stories/Font.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import Font from './Font'; diff --git a/code/frameworks/nextjs/template/stories/Head.stories.tsx b/code/frameworks/nextjs/template/stories/Head.stories.tsx index 540d0e04dc3d..f5f9d4629bff 100644 --- a/code/frameworks/nextjs/template/stories/Head.stories.tsx +++ b/code/frameworks/nextjs/template/stories/Head.stories.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, waitFor } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import Head from 'next/head'; +import { expect, waitFor } from 'storybook/test'; function Component() { return ( diff --git a/code/frameworks/nextjs/template/stories/Image.stories.tsx b/code/frameworks/nextjs/template/stories/Image.stories.tsx index ebceacaf1300..61676d6896f9 100644 --- a/code/frameworks/nextjs/template/stories/Image.stories.tsx +++ b/code/frameworks/nextjs/template/stories/Image.stories.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import Image from 'next/image'; diff --git a/code/frameworks/nextjs/template/stories/ImageLegacy.stories.tsx b/code/frameworks/nextjs/template/stories/ImageLegacy.stories.tsx index 954bc36a260f..bea2df97b729 100644 --- a/code/frameworks/nextjs/template/stories/ImageLegacy.stories.tsx +++ b/code/frameworks/nextjs/template/stories/ImageLegacy.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import Image from 'next/legacy/image'; diff --git a/code/frameworks/nextjs/template/stories/Link.stories.tsx b/code/frameworks/nextjs/template/stories/Link.stories.tsx index d071539c57a5..f9e1fd044f8e 100644 --- a/code/frameworks/nextjs/template/stories/Link.stories.tsx +++ b/code/frameworks/nextjs/template/stories/Link.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import Link from 'next/link'; diff --git a/code/frameworks/nextjs/template/stories/Navigation.stories.tsx b/code/frameworks/nextjs/template/stories/Navigation.stories.tsx index 5c4872d1ac31..e0dfa4e05793 100644 --- a/code/frameworks/nextjs/template/stories/Navigation.stories.tsx +++ b/code/frameworks/nextjs/template/stories/Navigation.stories.tsx @@ -1,8 +1,7 @@ import React from 'react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import { getRouter } from '@storybook/nextjs/navigation.mock'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; import { useParams, @@ -12,6 +11,7 @@ import { useSelectedLayoutSegment, useSelectedLayoutSegments, } from 'next/navigation'; +import { expect, userEvent, within } from 'storybook/test'; function Component() { const router = useRouter(); diff --git a/code/frameworks/nextjs/template/stories/RSC.stories.tsx b/code/frameworks/nextjs/template/stories/RSC.stories.tsx index 655a5f1a93e4..f8ba1dc120a1 100644 --- a/code/frameworks/nextjs/template/stories/RSC.stories.tsx +++ b/code/frameworks/nextjs/template/stories/RSC.stories.tsx @@ -1,7 +1,7 @@ /* eslint-disable local-rules/no-uncategorized-errors */ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import { Nested, RSC } from './RSC'; diff --git a/code/frameworks/nextjs/template/stories/Router.stories.tsx b/code/frameworks/nextjs/template/stories/Router.stories.tsx index d6586364fd0f..3ad0d29dd892 100644 --- a/code/frameworks/nextjs/template/stories/Router.stories.tsx +++ b/code/frameworks/nextjs/template/stories/Router.stories.tsx @@ -1,10 +1,10 @@ import React from 'react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import { getRouter } from '@storybook/nextjs/router.mock'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; import Router, { useRouter } from 'next/router'; +import { expect, userEvent, within } from 'storybook/test'; function Component() { const router = useRouter(); diff --git a/code/frameworks/nextjs/template/stories/StyledJsx.stories.tsx b/code/frameworks/nextjs/template/stories/StyledJsx.stories.tsx index 31adea42456c..a213c13928d7 100644 --- a/code/frameworks/nextjs/template/stories/StyledJsx.stories.tsx +++ b/code/frameworks/nextjs/template/stories/StyledJsx.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; const Component = () => (
diff --git a/code/frameworks/nextjs/template/stories_nextjs-default-ts/GetImageProps.stories.tsx b/code/frameworks/nextjs/template/stories_nextjs-default-ts/GetImageProps.stories.tsx index aefc27f54cfd..abd21cab7079 100644 --- a/code/frameworks/nextjs/template/stories_nextjs-default-ts/GetImageProps.stories.tsx +++ b/code/frameworks/nextjs/template/stories_nextjs-default-ts/GetImageProps.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import { getImageProps } from 'next/image'; diff --git a/code/frameworks/nextjs/template/stories_nextjs-default-ts/NextHeader.stories.tsx b/code/frameworks/nextjs/template/stories_nextjs-default-ts/NextHeader.stories.tsx index f5e83ef867f6..5478d835d89c 100644 --- a/code/frameworks/nextjs/template/stories_nextjs-default-ts/NextHeader.stories.tsx +++ b/code/frameworks/nextjs/template/stories_nextjs-default-ts/NextHeader.stories.tsx @@ -1,6 +1,7 @@ +import type { Meta, StoryObj } from '@storybook/nextjs'; import { cookies, headers } from '@storybook/nextjs/headers.mock'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; + +import { expect, userEvent, within } from 'storybook/test'; import NextHeader from './NextHeader'; diff --git a/code/frameworks/nextjs/template/stories_nextjs-default-ts/Redirect.stories.tsx b/code/frameworks/nextjs/template/stories_nextjs-default-ts/Redirect.stories.tsx index 3c5980b79757..6cf56ede2f13 100644 --- a/code/frameworks/nextjs/template/stories_nextjs-default-ts/Redirect.stories.tsx +++ b/code/frameworks/nextjs/template/stories_nextjs-default-ts/Redirect.stories.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import { redirect } from 'next/navigation'; +import { userEvent, within } from 'storybook/test'; let state = 'Bug! Not invalidated'; diff --git a/code/frameworks/nextjs/template/stories_nextjs-default-ts/ServerActions.stories.tsx b/code/frameworks/nextjs/template/stories_nextjs-default-ts/ServerActions.stories.tsx index f1a9ad762eed..4da326d7d98f 100644 --- a/code/frameworks/nextjs/template/stories_nextjs-default-ts/ServerActions.stories.tsx +++ b/code/frameworks/nextjs/template/stories_nextjs-default-ts/ServerActions.stories.tsx @@ -1,10 +1,11 @@ import React from 'react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import { revalidatePath } from '@storybook/nextjs/cache.mock'; import { cookies } from '@storybook/nextjs/headers.mock'; import { getRouter, redirect } from '@storybook/nextjs/navigation.mock'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, waitFor, within } from '@storybook/test'; + +import { expect, userEvent, waitFor, within } from 'storybook/test'; import { accessRoute, login, logout } from './server-actions'; diff --git a/code/frameworks/nextjs/template/stories_nextjs-prerelease/GetImageProps.stories.tsx b/code/frameworks/nextjs/template/stories_nextjs-prerelease/GetImageProps.stories.tsx index aefc27f54cfd..abd21cab7079 100644 --- a/code/frameworks/nextjs/template/stories_nextjs-prerelease/GetImageProps.stories.tsx +++ b/code/frameworks/nextjs/template/stories_nextjs-prerelease/GetImageProps.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import { getImageProps } from 'next/image'; diff --git a/code/frameworks/nextjs/template/stories_nextjs-prerelease/NextHeader.stories.tsx b/code/frameworks/nextjs/template/stories_nextjs-prerelease/NextHeader.stories.tsx index f5e83ef867f6..5478d835d89c 100644 --- a/code/frameworks/nextjs/template/stories_nextjs-prerelease/NextHeader.stories.tsx +++ b/code/frameworks/nextjs/template/stories_nextjs-prerelease/NextHeader.stories.tsx @@ -1,6 +1,7 @@ +import type { Meta, StoryObj } from '@storybook/nextjs'; import { cookies, headers } from '@storybook/nextjs/headers.mock'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; + +import { expect, userEvent, within } from 'storybook/test'; import NextHeader from './NextHeader'; diff --git a/code/frameworks/nextjs/template/stories_nextjs-prerelease/Redirect.stories.tsx b/code/frameworks/nextjs/template/stories_nextjs-prerelease/Redirect.stories.tsx index 3c5980b79757..6cf56ede2f13 100644 --- a/code/frameworks/nextjs/template/stories_nextjs-prerelease/Redirect.stories.tsx +++ b/code/frameworks/nextjs/template/stories_nextjs-prerelease/Redirect.stories.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { userEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import { redirect } from 'next/navigation'; +import { userEvent, within } from 'storybook/test'; let state = 'Bug! Not invalidated'; diff --git a/code/frameworks/nextjs/template/stories_nextjs-prerelease/ServerActions.stories.tsx b/code/frameworks/nextjs/template/stories_nextjs-prerelease/ServerActions.stories.tsx index f1a9ad762eed..4da326d7d98f 100644 --- a/code/frameworks/nextjs/template/stories_nextjs-prerelease/ServerActions.stories.tsx +++ b/code/frameworks/nextjs/template/stories_nextjs-prerelease/ServerActions.stories.tsx @@ -1,10 +1,11 @@ import React from 'react'; +import type { Meta, StoryObj } from '@storybook/nextjs'; import { revalidatePath } from '@storybook/nextjs/cache.mock'; import { cookies } from '@storybook/nextjs/headers.mock'; import { getRouter, redirect } from '@storybook/nextjs/navigation.mock'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, waitFor, within } from '@storybook/test'; + +import { expect, userEvent, waitFor, within } from 'storybook/test'; import { accessRoute, login, logout } from './server-actions'; diff --git a/code/frameworks/preact-vite/src/index.ts b/code/frameworks/preact-vite/src/index.ts index fcb073fefcd6..6a07f64e6833 100644 --- a/code/frameworks/preact-vite/src/index.ts +++ b/code/frameworks/preact-vite/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/preact'; export * from './types'; diff --git a/code/frameworks/preact-webpack5/src/index.ts b/code/frameworks/preact-webpack5/src/index.ts index fcb073fefcd6..6a07f64e6833 100644 --- a/code/frameworks/preact-webpack5/src/index.ts +++ b/code/frameworks/preact-webpack5/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/preact'; export * from './types'; diff --git a/code/frameworks/react-native-web-vite/src/index.ts b/code/frameworks/react-native-web-vite/src/index.ts index baac63e5f100..274fe088be34 100644 --- a/code/frameworks/react-native-web-vite/src/index.ts +++ b/code/frameworks/react-native-web-vite/src/index.ts @@ -1,3 +1,4 @@ export type { FrameworkOptions, StorybookConfig } from './types'; export { __definePreview as definePreview } from '@storybook/react'; +export * from '@storybook/react'; diff --git a/code/frameworks/react-native-web-vite/template/cli/js/Button.stories.jsx b/code/frameworks/react-native-web-vite/template/cli/js/Button.stories.jsx index b7136fd8ae67..3ea891e65ce3 100644 --- a/code/frameworks/react-native-web-vite/template/cli/js/Button.stories.jsx +++ b/code/frameworks/react-native-web-vite/template/cli/js/Button.stories.jsx @@ -1,6 +1,5 @@ -import { fn } from '@storybook/test'; - import { View } from 'react-native'; +import { fn } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/frameworks/react-native-web-vite/template/cli/js/Page.stories.jsx b/code/frameworks/react-native-web-vite/template/cli/js/Page.stories.jsx index 249647fce862..bbf8729b8a31 100644 --- a/code/frameworks/react-native-web-vite/template/cli/js/Page.stories.jsx +++ b/code/frameworks/react-native-web-vite/template/cli/js/Page.stories.jsx @@ -1,4 +1,4 @@ -import { expect, userEvent, within } from '@storybook/test'; +import { expect, userEvent, within } from 'storybook/test'; import { Page } from './Page'; diff --git a/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Button.stories.tsx b/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Button.stories.tsx index 8e655fbfe266..3d532efa99b7 100644 --- a/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Button.stories.tsx +++ b/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Button.stories.tsx @@ -1,7 +1,7 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-native-web-vite'; import { View } from 'react-native'; +import { fn } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Header.stories.tsx b/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Header.stories.tsx index 029f040b0396..b5a633e2e987 100644 --- a/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Header.stories.tsx +++ b/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Header.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-native-web-vite'; import { Header } from './Header'; diff --git a/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Page.stories.tsx b/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Page.stories.tsx index 5a5db7ff2685..bb9b828da45e 100644 --- a/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Page.stories.tsx +++ b/code/frameworks/react-native-web-vite/template/cli/ts-4-9/Page.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; +import type { Meta } from '@storybook/react-native-web-vite'; + +import { expect, userEvent, within } from 'storybook/test'; import { Page } from './Page'; diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index 5d3501d75dcc..c9ff913ecf15 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -56,6 +56,7 @@ }, "files": [ "dist/**/*", + "template/**/*", "README.md", "*.js", "*.d.ts", @@ -82,17 +83,11 @@ "vite": "^4.0.0" }, "peerDependencies": { - "@storybook/test": "workspace:*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "storybook": "workspace:^", "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" }, - "peerDependenciesMeta": { - "@storybook/test": { - "optional": true - } - }, "engines": { "node": ">=18.0.0" }, diff --git a/code/frameworks/react-vite/src/index.ts b/code/frameworks/react-vite/src/index.ts index f71bd648bf9c..cb9de933e712 100644 --- a/code/frameworks/react-vite/src/index.ts +++ b/code/frameworks/react-vite/src/index.ts @@ -1,3 +1,4 @@ +export * from '@storybook/react'; export { __definePreview as definePreview } from '@storybook/react'; export * from './types'; diff --git a/code/frameworks/react-vite/template/cli/.eslintrc.json b/code/frameworks/react-vite/template/cli/.eslintrc.json new file mode 100644 index 000000000000..40ece4a0aa18 --- /dev/null +++ b/code/frameworks/react-vite/template/cli/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "import/extensions": "off" + } +} diff --git a/code/frameworks/react-vite/template/cli/js/Button.jsx b/code/frameworks/react-vite/template/cli/js/Button.jsx new file mode 100644 index 000000000000..dabe38e0e82a --- /dev/null +++ b/code/frameworks/react-vite/template/cli/js/Button.jsx @@ -0,0 +1,39 @@ +import React from 'react'; + +import PropTypes from 'prop-types'; + +import './button.css'; + +/** Primary UI component for user interaction */ +export const Button = ({ + primary = false, + backgroundColor = null, + size = 'medium', + label, + ...props +}) => { + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + return ( + + ); +}; + +Button.propTypes = { + /** Is this the principal call to action on the page? */ + primary: PropTypes.bool, + /** What background color to use */ + backgroundColor: PropTypes.string, + /** How large should the button be? */ + size: PropTypes.oneOf(['small', 'medium', 'large']), + /** Button contents */ + label: PropTypes.string.isRequired, + /** Optional click handler */ + onClick: PropTypes.func, +}; diff --git a/code/frameworks/react-vite/template/cli/js/Button.stories.js b/code/frameworks/react-vite/template/cli/js/Button.stories.js new file mode 100644 index 000000000000..1b56021e71d9 --- /dev/null +++ b/code/frameworks/react-vite/template/cli/js/Button.stories.js @@ -0,0 +1,49 @@ +import { fn } from 'storybook/test'; + +import { Button } from './Button'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export +export default { + title: 'Example/Button', + component: Button, + parameters: { + // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout + layout: 'centered', + }, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + // More on argTypes: https://storybook.js.org/docs/api/argtypes + argTypes: { + backgroundColor: { control: 'color' }, + }, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + args: { onClick: fn() }, +}; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary = { + args: { + label: 'Button', + }, +}; + +export const Large = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/react-vite/template/cli/js/Header.jsx b/code/frameworks/react-vite/template/cli/js/Header.jsx new file mode 100644 index 000000000000..94a691e1dd76 --- /dev/null +++ b/code/frameworks/react-vite/template/cli/js/Header.jsx @@ -0,0 +1,56 @@ +import React from 'react'; + +import PropTypes from 'prop-types'; + +import { Button } from './Button'; +import './header.css'; + +export const Header = ({ user = null, onLogin, onLogout, onCreateAccount }) => ( +
+
+
+ + + + + + + +

Acme

+
+
+ {user ? ( + <> + + Welcome, {user.name}! + +
+
+
+); + +Header.propTypes = { + user: PropTypes.shape({ + name: PropTypes.string.isRequired, + }), + onLogin: PropTypes.func.isRequired, + onLogout: PropTypes.func.isRequired, + onCreateAccount: PropTypes.func.isRequired, +}; diff --git a/code/frameworks/react-vite/template/cli/js/Header.stories.js b/code/frameworks/react-vite/template/cli/js/Header.stories.js new file mode 100644 index 000000000000..6d88e1007498 --- /dev/null +++ b/code/frameworks/react-vite/template/cli/js/Header.stories.js @@ -0,0 +1,29 @@ +import { fn } from 'storybook/test'; + +import { Header } from './Header'; + +export default { + title: 'Example/Header', + component: Header, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, +}; + +export const LoggedIn = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut = {}; diff --git a/code/frameworks/react-vite/template/cli/js/Page.jsx b/code/frameworks/react-vite/template/cli/js/Page.jsx new file mode 100644 index 000000000000..c421401138ed --- /dev/null +++ b/code/frameworks/react-vite/template/cli/js/Page.jsx @@ -0,0 +1,69 @@ +import React from 'react'; + +import { Header } from './Header'; +import './page.css'; + +export const Page = () => { + const [user, setUser] = React.useState(); + + return ( +
+
setUser({ name: 'Jane Doe' })} + onLogout={() => setUser(undefined)} + onCreateAccount={() => setUser({ name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a{' '} + + component-driven + {' '} + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page + data in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at{' '} + + Storybook tutorials + + . Read more in the{' '} + + docs + + . +

+
+ Tip Adjust the width of the canvas with the{' '} + + + + + + Viewports addon in the toolbar +
+
+
+ ); +}; diff --git a/code/frameworks/react-vite/template/cli/js/Page.stories.js b/code/frameworks/react-vite/template/cli/js/Page.stories.js new file mode 100644 index 000000000000..7b9906a73514 --- /dev/null +++ b/code/frameworks/react-vite/template/cli/js/Page.stories.js @@ -0,0 +1,28 @@ +import { expect, userEvent, within } from '@storybook/test'; + +import { Page } from './Page'; + +export default { + title: 'Example/Page', + component: Page, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +}; + +export const LoggedOut = {}; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await expect(loginButton).not.toBeInTheDocument(); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; diff --git a/code/frameworks/react-vite/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/react-vite/template/cli/ts-4-9/Button.stories.ts new file mode 100644 index 000000000000..0c3151f3089c --- /dev/null +++ b/code/frameworks/react-vite/template/cli/ts-4-9/Button.stories.ts @@ -0,0 +1,54 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; + +import { Button } from './Button'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export +const meta = { + title: 'Example/Button', + component: Button, + parameters: { + // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout + layout: 'centered', + }, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + // More on argTypes: https://storybook.js.org/docs/api/argtypes + argTypes: { + backgroundColor: { control: 'color' }, + }, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + args: { onClick: fn() }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary: Story = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary: Story = { + args: { + label: 'Button', + }, +}; + +export const Large: Story = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small: Story = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/react-vite/template/cli/ts-4-9/Button.tsx b/code/frameworks/react-vite/template/cli/ts-4-9/Button.tsx new file mode 100644 index 000000000000..f35dafdcb427 --- /dev/null +++ b/code/frameworks/react-vite/template/cli/ts-4-9/Button.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +import './button.css'; + +export interface ButtonProps { + /** Is this the principal call to action on the page? */ + primary?: boolean; + /** What background color to use */ + backgroundColor?: string; + /** How large should the button be? */ + size?: 'small' | 'medium' | 'large'; + /** Button contents */ + label: string; + /** Optional click handler */ + onClick?: () => void; +} + +/** Primary UI component for user interaction */ +export const Button = ({ + primary = false, + size = 'medium', + backgroundColor, + label, + ...props +}: ButtonProps) => { + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + return ( + + ); +}; diff --git a/code/frameworks/react-vite/template/cli/ts-4-9/Header.stories.ts b/code/frameworks/react-vite/template/cli/ts-4-9/Header.stories.ts new file mode 100644 index 000000000000..36a3b8f9f2b1 --- /dev/null +++ b/code/frameworks/react-vite/template/cli/ts-4-9/Header.stories.ts @@ -0,0 +1,34 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; + +import { Header } from './Header'; + +const meta = { + title: 'Example/Header', + component: Header, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut: Story = {}; diff --git a/code/frameworks/react-vite/template/cli/ts-4-9/Header.tsx b/code/frameworks/react-vite/template/cli/ts-4-9/Header.tsx new file mode 100644 index 000000000000..1bf981a4251f --- /dev/null +++ b/code/frameworks/react-vite/template/cli/ts-4-9/Header.tsx @@ -0,0 +1,56 @@ +import React from 'react'; + +import { Button } from './Button'; +import './header.css'; + +type User = { + name: string; +}; + +export interface HeaderProps { + user?: User; + onLogin?: () => void; + onLogout?: () => void; + onCreateAccount?: () => void; +} + +export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => ( +
+
+
+ + + + + + + +

Acme

+
+
+ {user ? ( + <> + + Welcome, {user.name}! + +
+
+
+); diff --git a/code/frameworks/react-vite/template/cli/ts-4-9/Page.stories.ts b/code/frameworks/react-vite/template/cli/ts-4-9/Page.stories.ts new file mode 100644 index 000000000000..9ca0d882bce3 --- /dev/null +++ b/code/frameworks/react-vite/template/cli/ts-4-9/Page.stories.ts @@ -0,0 +1,33 @@ +import { expect, userEvent, within } from '@storybook/test'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { Page } from './Page'; + +const meta = { + title: 'Example/Page', + component: Page, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedOut: Story = {}; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await expect(loginButton).not.toBeInTheDocument(); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; diff --git a/code/frameworks/react-vite/template/cli/ts-4-9/Page.tsx b/code/frameworks/react-vite/template/cli/ts-4-9/Page.tsx new file mode 100644 index 000000000000..e11748301390 --- /dev/null +++ b/code/frameworks/react-vite/template/cli/ts-4-9/Page.tsx @@ -0,0 +1,73 @@ +import React from 'react'; + +import { Header } from './Header'; +import './page.css'; + +type User = { + name: string; +}; + +export const Page: React.FC = () => { + const [user, setUser] = React.useState(); + + return ( +
+
setUser({ name: 'Jane Doe' })} + onLogout={() => setUser(undefined)} + onCreateAccount={() => setUser({ name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a{' '} + + component-driven + {' '} + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page + data in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at{' '} + + Storybook tutorials + + . Read more in the{' '} + + docs + + . +

+
+ Tip Adjust the width of the canvas with the{' '} + + + + + + Viewports addon in the toolbar +
+
+
+ ); +}; diff --git a/code/frameworks/react-webpack5/src/index.ts b/code/frameworks/react-webpack5/src/index.ts index 9dce8313193a..cf6d4c05ce5a 100644 --- a/code/frameworks/react-webpack5/src/index.ts +++ b/code/frameworks/react-webpack5/src/index.ts @@ -1,2 +1,3 @@ +export * from '@storybook/react'; export * from './types'; export { __definePreview as definePreview } from '@storybook/react'; diff --git a/code/frameworks/server-webpack5/src/index.ts b/code/frameworks/server-webpack5/src/index.ts index fcb073fefcd6..098058fdbc0e 100644 --- a/code/frameworks/server-webpack5/src/index.ts +++ b/code/frameworks/server-webpack5/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/server'; export * from './types'; diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index d3e292d40514..a29ea282b3a9 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -43,6 +43,7 @@ "types": "dist/index.d.ts", "files": [ "dist/**/*", + "template/**/*", "README.md", "*.js", "*.d.ts", @@ -57,7 +58,7 @@ "@storybook/svelte": "workspace:*", "magic-string": "^0.30.0", "svelte-preprocess": "^5.1.1", - "svelte2tsx": "^0.7.13", + "svelte2tsx": "^0.7.35", "sveltedoc-parser": "^4.2.1", "ts-dedent": "^2.2.0", "typescript": "^4.9.4 || ^5.0.0" diff --git a/code/frameworks/svelte-vite/src/index.ts b/code/frameworks/svelte-vite/src/index.ts index fcb073fefcd6..07de4359ae11 100644 --- a/code/frameworks/svelte-vite/src/index.ts +++ b/code/frameworks/svelte-vite/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/svelte'; export * from './types'; diff --git a/code/frameworks/svelte-vite/src/plugins/generateDocgen.ts b/code/frameworks/svelte-vite/src/plugins/generateDocgen.ts index eff343fbfe0b..01905776d96e 100644 --- a/code/frameworks/svelte-vite/src/plugins/generateDocgen.ts +++ b/code/frameworks/svelte-vite/src/plugins/generateDocgen.ts @@ -1,6 +1,6 @@ import path from 'node:path'; -import svelte2tsx from 'svelte2tsx'; +import svelte2tsx, { internalHelpers } from 'svelte2tsx'; import { VERSION } from 'svelte/compiler'; import ts from 'typescript'; @@ -411,7 +411,9 @@ export function generateDocgen(targetFileName: string, cache: DocgenCache): Docg // Get render function generated by svelte2tsx const renderFunction = sourceFile.statements.find((statement) => { - return ts.isFunctionDeclaration(statement) && statement.name?.text === 'render'; + return ( + ts.isFunctionDeclaration(statement) && statement.name?.text === internalHelpers.renderName + ); }) as ts.FunctionDeclaration | undefined; if (renderFunction === undefined) { return { diff --git a/code/frameworks/svelte-vite/src/plugins/svelte-docgen.ts b/code/frameworks/svelte-vite/src/plugins/svelte-docgen.ts index c1647653933f..062e7f683277 100644 --- a/code/frameworks/svelte-vite/src/plugins/svelte-docgen.ts +++ b/code/frameworks/svelte-vite/src/plugins/svelte-docgen.ts @@ -146,7 +146,7 @@ export async function svelteDocgen(svelteOptions: Record = {}): Pro return { name: 'storybook:svelte-docgen-plugin', async transform(src: string, id: string) { - if (!filter(id)) { + if (id.startsWith('\0') || !filter(id)) { return undefined; } @@ -189,7 +189,13 @@ export async function svelteDocgen(svelteOptions: Record = {}): Pro let docOptions; if (docPreprocessOptions) { - const rawSource = readFileSync(resource).toString(); + let rawSource; + try { + rawSource = readFileSync(resource).toString(); + } catch (_) { + // ignore/skip modules that can't be loaded, possibly virtual module + return undefined; + } const { code: fileContent } = await preprocess(rawSource, docPreprocessOptions, { filename: resource, }); diff --git a/code/frameworks/svelte-vite/template/cli/js/Button.stories.js b/code/frameworks/svelte-vite/template/cli/js/Button.stories.js new file mode 100644 index 000000000000..c5c88776d6b5 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/js/Button.stories.js @@ -0,0 +1,43 @@ +import Button from './Button.svelte'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +export default { + title: 'Example/Button', + component: Button, + tags: ['autodocs'], + argTypes: { + backgroundColor: { control: 'color' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + }, + }, +}; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary = { + args: { + label: 'Button', + }, +}; + +export const Large = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/svelte-vite/template/cli/js/Button.svelte b/code/frameworks/svelte-vite/template/cli/js/Button.svelte new file mode 100644 index 000000000000..a2a78d9d0d6f --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/js/Button.svelte @@ -0,0 +1,36 @@ + + + diff --git a/code/frameworks/svelte-vite/template/cli/js/Header.stories.js b/code/frameworks/svelte-vite/template/cli/js/Header.stories.js new file mode 100644 index 000000000000..e2856c0e035c --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/js/Header.stories.js @@ -0,0 +1,22 @@ +import Header from './Header.svelte'; + +export default { + title: 'Example/Header', + component: Header, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +}; + +export const LoggedIn = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut = {}; diff --git a/code/frameworks/svelte-vite/template/cli/js/Header.svelte b/code/frameworks/svelte-vite/template/cli/js/Header.svelte new file mode 100644 index 000000000000..a9c08f75db7d --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/js/Header.svelte @@ -0,0 +1,52 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/svelte-vite/template/cli/js/Page.stories.js b/code/frameworks/svelte-vite/template/cli/js/Page.stories.js new file mode 100644 index 000000000000..5ce7b3dac56f --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/js/Page.stories.js @@ -0,0 +1,28 @@ +import { expect, userEvent, waitFor, within } from '@storybook/test'; + +import Page from './Page.svelte'; + +export default { + title: 'Example/Page', + component: Page, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +}; + +export const LoggedOut = {}; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; diff --git a/code/frameworks/svelte-vite/template/cli/js/Page.svelte b/code/frameworks/svelte-vite/template/cli/js/Page.svelte new file mode 100644 index 000000000000..acc473c2518f --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/js/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + on:logout={() => (user = null)} + on:createAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-js/Button.stories.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Button.stories.svelte new file mode 100644 index 000000000000..e6fb72dac174 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Button.stories.svelte @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-js/Button.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Button.svelte new file mode 100644 index 000000000000..b2b820ea4971 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Button.svelte @@ -0,0 +1,26 @@ + + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-js/Header.stories.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Header.stories.svelte new file mode 100644 index 000000000000..23175a8203e5 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Header.stories.svelte @@ -0,0 +1,26 @@ + + + + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-js/Header.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Header.svelte new file mode 100644 index 000000000000..dba3b7880f49 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Header.svelte @@ -0,0 +1,47 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-js/Page.stories.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Page.stories.svelte new file mode 100644 index 000000000000..2f4fd9e890a5 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Page.stories.svelte @@ -0,0 +1,30 @@ + + + { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }} + /> + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-js/Page.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Page.svelte new file mode 100644 index 000000000000..92a95c00c5c5 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-js/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + onLogout={() => (user = null)} + onCreateAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Button.stories.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Button.stories.svelte new file mode 100644 index 000000000000..e6fb72dac174 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Button.stories.svelte @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Button.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Button.svelte new file mode 100644 index 000000000000..b31f5bffe4a5 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Button.svelte @@ -0,0 +1,29 @@ + + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Header.stories.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Header.stories.svelte new file mode 100644 index 000000000000..23175a8203e5 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Header.stories.svelte @@ -0,0 +1,26 @@ + + + + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Header.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Header.svelte new file mode 100644 index 000000000000..14e890c79e98 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Header.svelte @@ -0,0 +1,45 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Page.stories.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Page.stories.svelte new file mode 100644 index 000000000000..f782871a1158 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Page.stories.svelte @@ -0,0 +1,30 @@ + + + { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }} +/> + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Page.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Page.svelte new file mode 100644 index 000000000000..c4c069a5a50b --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-3-8/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + onLogout={() => (user = undefined)} + onCreateAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Button.stories.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Button.stories.svelte new file mode 100644 index 000000000000..e6fb72dac174 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Button.stories.svelte @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Button.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Button.svelte new file mode 100644 index 000000000000..b31f5bffe4a5 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Button.svelte @@ -0,0 +1,29 @@ + + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Header.stories.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Header.stories.svelte new file mode 100644 index 000000000000..23175a8203e5 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Header.stories.svelte @@ -0,0 +1,26 @@ + + + + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Header.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Header.svelte new file mode 100644 index 000000000000..14e890c79e98 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Header.svelte @@ -0,0 +1,45 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Page.stories.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Page.stories.svelte new file mode 100644 index 000000000000..f782871a1158 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Page.stories.svelte @@ -0,0 +1,30 @@ + + + { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }} +/> + + diff --git a/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Page.svelte b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Page.svelte new file mode 100644 index 000000000000..c4c069a5a50b --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/svelte-5-ts-4-9/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + onLogout={() => (user = undefined)} + onCreateAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/svelte-vite/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/svelte-vite/template/cli/ts-4-9/Button.stories.ts new file mode 100644 index 000000000000..bcc54cde4d55 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/ts-4-9/Button.stories.ts @@ -0,0 +1,48 @@ +import type { Meta, StoryObj } from '@storybook/svelte-vite'; + +import Button from './Button.svelte'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +const meta = { + title: 'Example/Button', + component: Button, + tags: ['autodocs'], + argTypes: { + backgroundColor: { control: 'color' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + }, + }, +} satisfies Meta diff --git a/code/frameworks/svelte-vite/template/cli/ts-4-9/Header.stories.ts b/code/frameworks/svelte-vite/template/cli/ts-4-9/Header.stories.ts new file mode 100644 index 000000000000..22e301266dbf --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/ts-4-9/Header.stories.ts @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from '@storybook/svelte-vite'; + +import Header from './Header.svelte'; + +const meta = { + title: 'Example/Header', + component: Header, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +} satisfies Meta
; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut: Story = {}; diff --git a/code/frameworks/svelte-vite/template/cli/ts-4-9/Header.svelte b/code/frameworks/svelte-vite/template/cli/ts-4-9/Header.svelte new file mode 100644 index 000000000000..cb6f82d5e666 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/ts-4-9/Header.svelte @@ -0,0 +1,52 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/svelte-vite/template/cli/ts-4-9/Page.stories.ts b/code/frameworks/svelte-vite/template/cli/ts-4-9/Page.stories.ts new file mode 100644 index 000000000000..d6b261fb5864 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/ts-4-9/Page.stories.ts @@ -0,0 +1,33 @@ +import { expect, userEvent, waitFor, within } from '@storybook/test'; + +import type { Meta, StoryObj } from '@storybook/svelte-vite'; + +import Page from './Page.svelte'; + +const meta = { + title: 'Example/Page', + component: Page, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedOut: Story = {}; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; diff --git a/code/frameworks/svelte-vite/template/cli/ts-4-9/Page.svelte b/code/frameworks/svelte-vite/template/cli/ts-4-9/Page.svelte new file mode 100644 index 000000000000..94cdb07ecd39 --- /dev/null +++ b/code/frameworks/svelte-vite/template/cli/ts-4-9/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + on:logout={() => (user = null)} + on:createAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index 7ac7af6decf2..55f2f14aa283 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -43,6 +43,7 @@ "types": "dist/index.d.ts", "files": [ "dist/**/*", + "templates/**/*", "README.md", "*.js", "*.d.ts", diff --git a/code/frameworks/svelte-webpack5/src/index.ts b/code/frameworks/svelte-webpack5/src/index.ts index fcb073fefcd6..07de4359ae11 100644 --- a/code/frameworks/svelte-webpack5/src/index.ts +++ b/code/frameworks/svelte-webpack5/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/svelte'; export * from './types'; diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index d3c602c9a1a5..8b972dc17a0c 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -54,6 +54,7 @@ "types": "dist/index.d.ts", "files": [ "dist/**/*", + "template/**/*", "README.md", "*.js", "*.d.ts", diff --git a/code/frameworks/sveltekit/src/index.ts b/code/frameworks/sveltekit/src/index.ts index a904f93ec89d..ee64168c3b83 100644 --- a/code/frameworks/sveltekit/src/index.ts +++ b/code/frameworks/sveltekit/src/index.ts @@ -1,2 +1,4 @@ +export * from '@storybook/svelte'; export * from './types'; +// @ts-expect-error (double exports) export * from './portable-stories'; diff --git a/code/frameworks/sveltekit/template/cli/js/Button.stories.js b/code/frameworks/sveltekit/template/cli/js/Button.stories.js new file mode 100644 index 000000000000..c5c88776d6b5 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/js/Button.stories.js @@ -0,0 +1,43 @@ +import Button from './Button.svelte'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +export default { + title: 'Example/Button', + component: Button, + tags: ['autodocs'], + argTypes: { + backgroundColor: { control: 'color' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + }, + }, +}; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary = { + args: { + label: 'Button', + }, +}; + +export const Large = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/sveltekit/template/cli/js/Button.svelte b/code/frameworks/sveltekit/template/cli/js/Button.svelte new file mode 100644 index 000000000000..a2a78d9d0d6f --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/js/Button.svelte @@ -0,0 +1,36 @@ + + + diff --git a/code/frameworks/sveltekit/template/cli/js/Header.stories.js b/code/frameworks/sveltekit/template/cli/js/Header.stories.js new file mode 100644 index 000000000000..e2856c0e035c --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/js/Header.stories.js @@ -0,0 +1,22 @@ +import Header from './Header.svelte'; + +export default { + title: 'Example/Header', + component: Header, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +}; + +export const LoggedIn = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut = {}; diff --git a/code/frameworks/sveltekit/template/cli/js/Header.svelte b/code/frameworks/sveltekit/template/cli/js/Header.svelte new file mode 100644 index 000000000000..a9c08f75db7d --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/js/Header.svelte @@ -0,0 +1,52 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/sveltekit/template/cli/js/Page.stories.js b/code/frameworks/sveltekit/template/cli/js/Page.stories.js new file mode 100644 index 000000000000..5ce7b3dac56f --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/js/Page.stories.js @@ -0,0 +1,28 @@ +import { expect, userEvent, waitFor, within } from '@storybook/test'; + +import Page from './Page.svelte'; + +export default { + title: 'Example/Page', + component: Page, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +}; + +export const LoggedOut = {}; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; diff --git a/code/frameworks/sveltekit/template/cli/js/Page.svelte b/code/frameworks/sveltekit/template/cli/js/Page.svelte new file mode 100644 index 000000000000..acc473c2518f --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/js/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + on:logout={() => (user = null)} + on:createAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-js/Button.stories.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-js/Button.stories.svelte new file mode 100644 index 000000000000..e6fb72dac174 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-js/Button.stories.svelte @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-js/Button.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-js/Button.svelte new file mode 100644 index 000000000000..b2b820ea4971 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-js/Button.svelte @@ -0,0 +1,26 @@ + + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-js/Header.stories.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-js/Header.stories.svelte new file mode 100644 index 000000000000..23175a8203e5 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-js/Header.stories.svelte @@ -0,0 +1,26 @@ + + + + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-js/Header.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-js/Header.svelte new file mode 100644 index 000000000000..dba3b7880f49 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-js/Header.svelte @@ -0,0 +1,47 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-js/Page.stories.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-js/Page.stories.svelte new file mode 100644 index 000000000000..2f4fd9e890a5 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-js/Page.stories.svelte @@ -0,0 +1,30 @@ + + + { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }} + /> + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-js/Page.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-js/Page.svelte new file mode 100644 index 000000000000..92a95c00c5c5 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-js/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + onLogout={() => (user = null)} + onCreateAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Button.stories.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Button.stories.svelte new file mode 100644 index 000000000000..e6fb72dac174 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Button.stories.svelte @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Button.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Button.svelte new file mode 100644 index 000000000000..b31f5bffe4a5 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Button.svelte @@ -0,0 +1,29 @@ + + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Header.stories.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Header.stories.svelte new file mode 100644 index 000000000000..23175a8203e5 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Header.stories.svelte @@ -0,0 +1,26 @@ + + + + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Header.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Header.svelte new file mode 100644 index 000000000000..14e890c79e98 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Header.svelte @@ -0,0 +1,45 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Page.stories.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Page.stories.svelte new file mode 100644 index 000000000000..f782871a1158 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Page.stories.svelte @@ -0,0 +1,30 @@ + + + { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }} +/> + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Page.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Page.svelte new file mode 100644 index 000000000000..c4c069a5a50b --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-3-8/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + onLogout={() => (user = undefined)} + onCreateAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Button.stories.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Button.stories.svelte new file mode 100644 index 000000000000..e6fb72dac174 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Button.stories.svelte @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Button.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Button.svelte new file mode 100644 index 000000000000..b31f5bffe4a5 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Button.svelte @@ -0,0 +1,29 @@ + + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Header.stories.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Header.stories.svelte new file mode 100644 index 000000000000..23175a8203e5 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Header.stories.svelte @@ -0,0 +1,26 @@ + + + + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Header.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Header.svelte new file mode 100644 index 000000000000..14e890c79e98 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Header.svelte @@ -0,0 +1,45 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Page.stories.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Page.stories.svelte new file mode 100644 index 000000000000..f782871a1158 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Page.stories.svelte @@ -0,0 +1,30 @@ + + + { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }} +/> + + diff --git a/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Page.svelte b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Page.svelte new file mode 100644 index 000000000000..c4c069a5a50b --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/svelte-5-ts-4-9/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + onLogout={() => (user = undefined)} + onCreateAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/sveltekit/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/sveltekit/template/cli/ts-4-9/Button.stories.ts new file mode 100644 index 000000000000..1b8ab10d8b7a --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/ts-4-9/Button.stories.ts @@ -0,0 +1,48 @@ +import type { Meta, StoryObj } from '@storybook/sveltekit'; + +import Button from './Button.svelte'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +const meta = { + title: 'Example/Button', + component: Button, + tags: ['autodocs'], + argTypes: { + backgroundColor: { control: 'color' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + }, + }, +} satisfies Meta diff --git a/code/frameworks/sveltekit/template/cli/ts-4-9/Header.stories.ts b/code/frameworks/sveltekit/template/cli/ts-4-9/Header.stories.ts new file mode 100644 index 000000000000..8f3588a55c1e --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/ts-4-9/Header.stories.ts @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from '@storybook/sveltekit'; + +import Header from './Header.svelte'; + +const meta = { + title: 'Example/Header', + component: Header, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +} satisfies Meta
; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut: Story = {}; diff --git a/code/frameworks/sveltekit/template/cli/ts-4-9/Header.svelte b/code/frameworks/sveltekit/template/cli/ts-4-9/Header.svelte new file mode 100644 index 000000000000..cb6f82d5e666 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/ts-4-9/Header.svelte @@ -0,0 +1,52 @@ + + +
+
+
+ + + + + + + +

Acme

+
+
+ {#if user} + + Welcome, {user.name}! + +
+
+
diff --git a/code/frameworks/sveltekit/template/cli/ts-4-9/Page.stories.ts b/code/frameworks/sveltekit/template/cli/ts-4-9/Page.stories.ts new file mode 100644 index 000000000000..0465cf531223 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/ts-4-9/Page.stories.ts @@ -0,0 +1,32 @@ +import type { Meta, StoryObj } from '@storybook/sveltekit'; +import { expect, userEvent, waitFor, within } from '@storybook/test'; + +import Page from './Page.svelte'; + +const meta = { + title: 'Example/Page', + component: Page, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedOut: Story = {}; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await waitFor(() => expect(loginButton).not.toBeInTheDocument()); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; diff --git a/code/frameworks/sveltekit/template/cli/ts-4-9/Page.svelte b/code/frameworks/sveltekit/template/cli/ts-4-9/Page.svelte new file mode 100644 index 000000000000..94cdb07ecd39 --- /dev/null +++ b/code/frameworks/sveltekit/template/cli/ts-4-9/Page.svelte @@ -0,0 +1,70 @@ + + +
+
(user = { name: 'Jane Doe' })} + on:logout={() => (user = null)} + on:createAccount={() => (user = { name: 'Jane Doe' })} + /> + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven + + process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip + Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/forms.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/forms.stories.js index baff059fa212..a60865e1d172 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/forms.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/forms.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Forms from './Forms.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/hrefs.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/hrefs.stories.js index 9f7033e36a3f..e5517ce62f88 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/hrefs.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/hrefs.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Hrefs from './Hrefs.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/navigation.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/navigation.stories.js index e102fce96438..cde66fd4f5a0 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/navigation.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-prerelease-ts/navigation.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Navigation from './Navigation.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/environment.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/environment.stories.js index fb4c85d99264..47f2f3a4424d 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/environment.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/environment.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Environment from './Environment.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/forms.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/forms.stories.js index 7659291df4f8..6a020c8e124c 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/forms.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/forms.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, userEvent, within } from '@storybook/test'; +import { expect, fn, userEvent, within } from 'storybook/test'; import Forms from './Forms.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/hrefs.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/hrefs.stories.js index 9f7033e36a3f..e5517ce62f88 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/hrefs.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/hrefs.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Hrefs from './Hrefs.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/navigation.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/navigation.stories.js index e102fce96438..cde66fd4f5a0 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/navigation.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/navigation.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Navigation from './Navigation.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/paths.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/paths.stories.js index 4ef5ddbcb54b..1c6d5f362c59 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/paths.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-js/paths.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Paths from './Paths.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/environment.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/environment.stories.js index fb4c85d99264..47f2f3a4424d 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/environment.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/environment.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Environment from './Environment.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/forms.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/forms.stories.js index baff059fa212..a60865e1d172 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/forms.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/forms.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Forms from './Forms.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/hrefs.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/hrefs.stories.js index 9f7033e36a3f..e5517ce62f88 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/hrefs.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/hrefs.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Hrefs from './Hrefs.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/navigation.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/navigation.stories.js index e102fce96438..cde66fd4f5a0 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/navigation.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/navigation.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Navigation from './Navigation.svelte'; diff --git a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/paths.stories.js b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/paths.stories.js index 4ef5ddbcb54b..1c6d5f362c59 100644 --- a/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/paths.stories.js +++ b/code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/paths.stories.js @@ -1,4 +1,4 @@ -import { expect, fn, within } from '@storybook/test'; +import { expect, fn, within } from 'storybook/test'; import Paths from './Paths.svelte'; diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index 49e0cc2aa711..dbdb637ea2d2 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -48,6 +48,7 @@ "types": "dist/index.d.ts", "files": [ "dist/**/*", + "template/**/*", "README.md", "*.js", "*.d.ts", diff --git a/code/frameworks/vue3-vite/src/index.ts b/code/frameworks/vue3-vite/src/index.ts index fcb073fefcd6..034adb8b02a6 100644 --- a/code/frameworks/vue3-vite/src/index.ts +++ b/code/frameworks/vue3-vite/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/vue3'; export * from './types'; diff --git a/code/frameworks/vue3-vite/template/cli/js/Button.stories.js b/code/frameworks/vue3-vite/template/cli/js/Button.stories.js new file mode 100644 index 000000000000..2bd009f38165 --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/js/Button.stories.js @@ -0,0 +1,44 @@ +import { fn } from 'storybook/test'; + +import MyButton from './Button.vue'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +export default { + title: 'Example/Button', + component: MyButton, + tags: ['autodocs'], + argTypes: { + size: { control: { type: 'select' }, options: ['small', 'medium', 'large'] }, + backgroundColor: { control: 'color' }, + }, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + args: { onClick: fn() }, +}; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary = { + args: { + label: 'Button', + }, +}; + +export const Large = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/vue3-vite/template/cli/js/Button.vue b/code/frameworks/vue3-vite/template/cli/js/Button.vue new file mode 100644 index 000000000000..a831ddf4991b --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/js/Button.vue @@ -0,0 +1,52 @@ + + + diff --git a/code/frameworks/vue3-vite/template/cli/js/Header.stories.js b/code/frameworks/vue3-vite/template/cli/js/Header.stories.js new file mode 100644 index 000000000000..ca1b5e65bf00 --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/js/Header.stories.js @@ -0,0 +1,48 @@ +import { fn } from 'storybook/test'; + +import MyHeader from './Header.vue'; + +export default { + title: 'Example/Header', + component: MyHeader, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + render: (args) => ({ + // Components used in your story `template` are defined in the `components` object + components: { + MyHeader, + }, + // The story's `args` need to be mapped into the template through the `setup()` method + setup() { + // Story args can be spread into the returned object + return { + ...args, + }; + }, + // Then, the spread values can be accessed directly in the template + template: '', + }), + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, +}; + +export const LoggedIn = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut = { + args: { + user: null, + }, +}; diff --git a/code/frameworks/vue3-vite/template/cli/js/Header.vue b/code/frameworks/vue3-vite/template/cli/js/Header.vue new file mode 100644 index 000000000000..16d7740d96c4 --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/js/Header.vue @@ -0,0 +1,59 @@ + + + diff --git a/code/frameworks/vue3-vite/template/cli/js/Page.stories.js b/code/frameworks/vue3-vite/template/cli/js/Page.stories.js new file mode 100644 index 000000000000..f03db3c7f07f --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/js/Page.stories.js @@ -0,0 +1,34 @@ +import { expect, userEvent, within } from '@storybook/test'; + +import MyPage from './Page.vue'; + +export default { + title: 'Example/Page', + component: MyPage, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +}; + +export const LoggedOut = {}; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn = { + render: () => ({ + components: { + MyPage, + }, + template: '', + }), + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await expect(loginButton).not.toBeInTheDocument(); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; diff --git a/code/frameworks/vue3-vite/template/cli/js/Page.vue b/code/frameworks/vue3-vite/template/cli/js/Page.vue new file mode 100644 index 000000000000..245401b72c4d --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/js/Page.vue @@ -0,0 +1,83 @@ + + + diff --git a/code/frameworks/vue3-vite/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/vue3-vite/template/cli/ts-4-9/Button.stories.ts new file mode 100644 index 000000000000..c9cf6edbe7de --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/ts-4-9/Button.stories.ts @@ -0,0 +1,57 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite'; + +import { fn } from 'storybook/test'; + +import Button from './Button.vue'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +const meta = { + title: 'Example/Button', + component: Button, + // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + argTypes: { + size: { control: 'select', options: ['small', 'medium', 'large'] }, + backgroundColor: { control: 'color' }, + }, + args: { + primary: false, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + onClick: fn(), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; +/* + *👇 Render functions are a framework specific feature to allow you control on how the component renders. + * See https://storybook.js.org/docs/api/csf + * to learn how to use render functions. + */ +export const Primary: Story = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary: Story = { + args: { + primary: false, + label: 'Button', + }, +}; + +export const Large: Story = { + args: { + label: 'Button', + size: 'large', + }, +}; + +export const Small: Story = { + args: { + label: 'Button', + size: 'small', + }, +}; diff --git a/code/frameworks/vue3-vite/template/cli/ts-4-9/Button.vue b/code/frameworks/vue3-vite/template/cli/ts-4-9/Button.vue new file mode 100644 index 000000000000..2e1ee0ee22f3 --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/ts-4-9/Button.vue @@ -0,0 +1,48 @@ + + + \ No newline at end of file diff --git a/code/frameworks/vue3-vite/template/cli/ts-4-9/Header.stories.ts b/code/frameworks/vue3-vite/template/cli/ts-4-9/Header.stories.ts new file mode 100644 index 000000000000..47caa29a09e3 --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/ts-4-9/Header.stories.ts @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite'; + +import { fn } from 'storybook/test'; + +import MyHeader from './Header.vue'; + +const meta = { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/configure/#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Example/Header', + component: MyHeader, + render: (args: any) => ({ + components: { MyHeader }, + setup() { + return { args }; + }, + template: '', + }), + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, + // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut: Story = { + args: { + user: null, + }, +}; diff --git a/code/frameworks/vue3-vite/template/cli/ts-4-9/Header.vue b/code/frameworks/vue3-vite/template/cli/ts-4-9/Header.vue new file mode 100644 index 000000000000..b716db02b3f5 --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/ts-4-9/Header.vue @@ -0,0 +1,37 @@ + + + + diff --git a/code/frameworks/vue3-vite/template/cli/ts-4-9/Page.stories.ts b/code/frameworks/vue3-vite/template/cli/ts-4-9/Page.stories.ts new file mode 100644 index 000000000000..906f674fa3a0 --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/ts-4-9/Page.stories.ts @@ -0,0 +1,39 @@ +import { expect, userEvent, within } from '@storybook/test'; + +import type { Meta, StoryObj } from '@storybook/vue3-vite'; + +import MyPage from './Page.vue'; + +const meta = { + title: 'Example/Page', + component: MyPage, + render: () => ({ + components: { MyPage }, + template: '', + }), + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, + // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn: Story = { + play: async ({ canvasElement }: any) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await expect(loginButton).not.toBeInTheDocument(); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; + +export const LoggedOut: Story = {}; diff --git a/code/frameworks/vue3-vite/template/cli/ts-4-9/Page.vue b/code/frameworks/vue3-vite/template/cli/ts-4-9/Page.vue new file mode 100644 index 000000000000..6a6e5eb1a4af --- /dev/null +++ b/code/frameworks/vue3-vite/template/cli/ts-4-9/Page.vue @@ -0,0 +1,73 @@ + + + diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json index 438e09442f17..c46b6f713875 100644 --- a/code/frameworks/vue3-webpack5/package.json +++ b/code/frameworks/vue3-webpack5/package.json @@ -43,6 +43,7 @@ "types": "dist/index.d.ts", "files": [ "dist/**/*", + "template/**/*", "README.md", "*.js", "*.d.ts", diff --git a/code/frameworks/vue3-webpack5/src/index.ts b/code/frameworks/vue3-webpack5/src/index.ts index fcb073fefcd6..034adb8b02a6 100644 --- a/code/frameworks/vue3-webpack5/src/index.ts +++ b/code/frameworks/vue3-webpack5/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/vue3'; export * from './types'; diff --git a/code/frameworks/vue3-webpack5/template/cli/js/Button.stories.js b/code/frameworks/vue3-webpack5/template/cli/js/Button.stories.js new file mode 100644 index 000000000000..2bd009f38165 --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/js/Button.stories.js @@ -0,0 +1,44 @@ +import { fn } from 'storybook/test'; + +import MyButton from './Button.vue'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +export default { + title: 'Example/Button', + component: MyButton, + tags: ['autodocs'], + argTypes: { + size: { control: { type: 'select' }, options: ['small', 'medium', 'large'] }, + backgroundColor: { control: 'color' }, + }, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + args: { onClick: fn() }, +}; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary = { + args: { + label: 'Button', + }, +}; + +export const Large = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/vue3-webpack5/template/cli/js/Button.vue b/code/frameworks/vue3-webpack5/template/cli/js/Button.vue new file mode 100644 index 000000000000..a831ddf4991b --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/js/Button.vue @@ -0,0 +1,52 @@ + + + diff --git a/code/frameworks/vue3-webpack5/template/cli/js/Header.stories.js b/code/frameworks/vue3-webpack5/template/cli/js/Header.stories.js new file mode 100644 index 000000000000..ca1b5e65bf00 --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/js/Header.stories.js @@ -0,0 +1,48 @@ +import { fn } from 'storybook/test'; + +import MyHeader from './Header.vue'; + +export default { + title: 'Example/Header', + component: MyHeader, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + render: (args) => ({ + // Components used in your story `template` are defined in the `components` object + components: { + MyHeader, + }, + // The story's `args` need to be mapped into the template through the `setup()` method + setup() { + // Story args can be spread into the returned object + return { + ...args, + }; + }, + // Then, the spread values can be accessed directly in the template + template: '', + }), + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, +}; + +export const LoggedIn = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut = { + args: { + user: null, + }, +}; diff --git a/code/frameworks/vue3-webpack5/template/cli/js/Header.vue b/code/frameworks/vue3-webpack5/template/cli/js/Header.vue new file mode 100644 index 000000000000..16d7740d96c4 --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/js/Header.vue @@ -0,0 +1,59 @@ + + + diff --git a/code/frameworks/vue3-webpack5/template/cli/js/Page.stories.js b/code/frameworks/vue3-webpack5/template/cli/js/Page.stories.js new file mode 100644 index 000000000000..f03db3c7f07f --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/js/Page.stories.js @@ -0,0 +1,34 @@ +import { expect, userEvent, within } from '@storybook/test'; + +import MyPage from './Page.vue'; + +export default { + title: 'Example/Page', + component: MyPage, + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, +}; + +export const LoggedOut = {}; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn = { + render: () => ({ + components: { + MyPage, + }, + template: '', + }), + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await expect(loginButton).not.toBeInTheDocument(); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; diff --git a/code/frameworks/vue3-webpack5/template/cli/js/Page.vue b/code/frameworks/vue3-webpack5/template/cli/js/Page.vue new file mode 100644 index 000000000000..245401b72c4d --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/js/Page.vue @@ -0,0 +1,83 @@ + + + diff --git a/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Button.stories.ts new file mode 100644 index 000000000000..73deaf7ecc03 --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Button.stories.ts @@ -0,0 +1,57 @@ +import type { Meta, StoryObj } from '@storybook/vue3-webpack5'; + +import { fn } from 'storybook/test'; + +import Button from './Button.vue'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +const meta = { + title: 'Example/Button', + component: Button, + // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + argTypes: { + size: { control: 'select', options: ['small', 'medium', 'large'] }, + backgroundColor: { control: 'color' }, + }, + args: { + primary: false, + // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + onClick: fn(), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; +/* + *👇 Render functions are a framework specific feature to allow you control on how the component renders. + * See https://storybook.js.org/docs/api/csf + * to learn how to use render functions. + */ +export const Primary: Story = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary: Story = { + args: { + primary: false, + label: 'Button', + }, +}; + +export const Large: Story = { + args: { + label: 'Button', + size: 'large', + }, +}; + +export const Small: Story = { + args: { + label: 'Button', + size: 'small', + }, +}; diff --git a/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Button.vue b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Button.vue new file mode 100644 index 000000000000..2e1ee0ee22f3 --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Button.vue @@ -0,0 +1,48 @@ + + + \ No newline at end of file diff --git a/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Header.stories.ts b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Header.stories.ts new file mode 100644 index 000000000000..5826d501c98b --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Header.stories.ts @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from '@storybook/vue3-webpack5'; + +import { fn } from 'storybook/test'; + +import MyHeader from './Header.vue'; + +const meta = { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/configure/#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Example/Header', + component: MyHeader, + render: (args: any) => ({ + components: { MyHeader }, + setup() { + return { args }; + }, + template: '', + }), + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, + // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut: Story = { + args: { + user: null, + }, +}; diff --git a/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Header.vue b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Header.vue new file mode 100644 index 000000000000..b716db02b3f5 --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Header.vue @@ -0,0 +1,37 @@ + + + + diff --git a/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Page.stories.ts b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Page.stories.ts new file mode 100644 index 000000000000..dfc690f896c5 --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Page.stories.ts @@ -0,0 +1,39 @@ +import { expect, userEvent, within } from '@storybook/test'; + +import type { Meta, StoryObj } from '@storybook/vue3-webpack5'; + +import MyPage from './Page.vue'; + +const meta = { + title: 'Example/Page', + component: MyPage, + render: () => ({ + components: { MyPage }, + template: '', + }), + parameters: { + // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout + layout: 'fullscreen', + }, + // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing +export const LoggedIn: Story = { + play: async ({ canvasElement }: any) => { + const canvas = within(canvasElement); + const loginButton = canvas.getByRole('button', { name: /Log in/i }); + await expect(loginButton).toBeInTheDocument(); + await userEvent.click(loginButton); + await expect(loginButton).not.toBeInTheDocument(); + + const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + await expect(logoutButton).toBeInTheDocument(); + }, +}; + +export const LoggedOut: Story = {}; diff --git a/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Page.vue b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Page.vue new file mode 100644 index 000000000000..6a6e5eb1a4af --- /dev/null +++ b/code/frameworks/vue3-webpack5/template/cli/ts-4-9/Page.vue @@ -0,0 +1,73 @@ + + + diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index 06537c129744..549bb897aac3 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -43,6 +43,7 @@ "types": "dist/index.d.ts", "files": [ "dist/**/*", + "template/**/*", "README.md", "*.js", "*.d.ts", diff --git a/code/frameworks/web-components-vite/src/index.ts b/code/frameworks/web-components-vite/src/index.ts index fcb073fefcd6..538d3b3a6d67 100644 --- a/code/frameworks/web-components-vite/src/index.ts +++ b/code/frameworks/web-components-vite/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/web-components'; export * from './types'; diff --git a/code/frameworks/web-components-vite/template/cli/.eslintrc.json b/code/frameworks/web-components-vite/template/cli/.eslintrc.json new file mode 100644 index 000000000000..40ece4a0aa18 --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "import/extensions": "off" + } +} diff --git a/code/frameworks/web-components-vite/template/cli/js/Button.js b/code/frameworks/web-components-vite/template/cli/js/Button.js new file mode 100644 index 000000000000..6cbe804eb1b7 --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/js/Button.js @@ -0,0 +1,20 @@ +import { html } from 'lit'; +import { styleMap } from 'lit/directives/style-map.js'; + +import './button.css'; + +/** Primary UI component for user interaction */ +export const Button = ({ primary, backgroundColor = null, size, label, onClick }) => { + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + + return html` + + `; +}; diff --git a/code/frameworks/web-components-vite/template/cli/js/Button.stories.js b/code/frameworks/web-components-vite/template/cli/js/Button.stories.js new file mode 100644 index 000000000000..9efdf07ece3d --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/js/Button.stories.js @@ -0,0 +1,46 @@ +import { fn } from 'storybook/test'; + +import { Button } from './Button'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +export default { + title: 'Example/Button', + tags: ['autodocs'], + render: (args) => Button(args), + argTypes: { + backgroundColor: { control: 'color' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + }, + }, + args: { onClick: fn() }, +}; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary = { + args: { + label: 'Button', + }, +}; + +export const Large = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/web-components-vite/template/cli/js/Header.js b/code/frameworks/web-components-vite/template/cli/js/Header.js new file mode 100644 index 000000000000..19fea63604a8 --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/js/Header.js @@ -0,0 +1,45 @@ +import { html } from 'lit'; + +import { Button } from './Button'; +import './header.css'; + +export const Header = ({ user, onLogin, onLogout, onCreateAccount }) => html` +
+
+
+ + + + + + + +

Acme

+
+
+ ${user + ? Button({ size: 'small', onClick: onLogout, label: 'Log out' }) + : html`${Button({ + size: 'small', + onClick: onLogin, + label: 'Log in', + })} + ${Button({ + primary: true, + size: 'small', + onClick: onCreateAccount, + label: 'Sign up', + })}`} +
+
+
+`; diff --git a/code/frameworks/web-components-vite/template/cli/js/Header.stories.js b/code/frameworks/web-components-vite/template/cli/js/Header.stories.js new file mode 100644 index 000000000000..b45ba68c5a87 --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/js/Header.stories.js @@ -0,0 +1,24 @@ +import { fn } from 'storybook/test'; + +import { Header } from './Header'; + +export default { + title: 'Example/Header', + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/web-components/vue/writing-docs/autodocs + tags: ['autodocs'], + render: (args) => Header(args), + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, +}; +export const LoggedIn = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut = {}; diff --git a/code/frameworks/web-components-vite/template/cli/js/Page.js b/code/frameworks/web-components-vite/template/cli/js/Page.js new file mode 100644 index 000000000000..54919dabd48b --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/js/Page.js @@ -0,0 +1,62 @@ +import { html } from 'lit'; + +import { Header } from './Header'; +import './page.css'; + +export const Page = ({ user, onLogin, onLogout, onCreateAccount }) => html` +
+ ${Header({ + user, + onLogin, + onLogout, + onCreateAccount, + })} + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
+`; diff --git a/code/frameworks/web-components-vite/template/cli/js/Page.stories.js b/code/frameworks/web-components-vite/template/cli/js/Page.stories.js new file mode 100644 index 000000000000..7c28c5ad14b3 --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/js/Page.stories.js @@ -0,0 +1,20 @@ +import * as HeaderStories from './Header.stories'; +import { Page } from './Page'; + +export default { + title: 'Example/Page', + render: (args) => Page(args), +}; + +export const LoggedIn = { + args: { + // More on composing args: https://storybook.js.org/docs/writing-stories/args#args-composition + ...HeaderStories.LoggedIn.args, + }, +}; + +export const LoggedOut = { + args: { + ...HeaderStories.LoggedOut.args, + }, +}; diff --git a/code/frameworks/web-components-vite/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/web-components-vite/template/cli/ts-4-9/Button.stories.ts new file mode 100644 index 000000000000..8b595baddc2c --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/ts-4-9/Button.stories.ts @@ -0,0 +1,52 @@ +import type { Meta, StoryObj } from '@storybook/web-components-vite'; + +import { fn } from 'storybook/test'; + +import type { ButtonProps } from './Button'; +import { Button } from './Button'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +const meta = { + title: 'Example/Button', + tags: ['autodocs'], + render: (args) => Button(args), + argTypes: { + backgroundColor: { control: 'color' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + }, + }, + args: { onClick: fn() }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary: Story = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary: Story = { + args: { + label: 'Button', + }, +}; + +export const Large: Story = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small: Story = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/web-components-vite/template/cli/ts-4-9/Button.ts b/code/frameworks/web-components-vite/template/cli/ts-4-9/Button.ts new file mode 100644 index 000000000000..4ca7fe4a7232 --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/ts-4-9/Button.ts @@ -0,0 +1,32 @@ +import { html } from 'lit'; +import { styleMap } from 'lit/directives/style-map.js'; + +import './button.css'; + +export interface ButtonProps { + /** Is this the principal call to action on the page? */ + primary?: boolean; + /** What background color to use */ + backgroundColor?: string; + /** How large should the button be? */ + size?: 'small' | 'medium' | 'large'; + /** Button contents */ + label: string; + /** Optional click handler */ + onClick?: () => void; +} +/** Primary UI component for user interaction */ +export const Button = ({ primary, backgroundColor, size, label, onClick }: ButtonProps) => { + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + + return html` + + `; +}; diff --git a/code/frameworks/web-components-vite/template/cli/ts-4-9/Header.stories.ts b/code/frameworks/web-components-vite/template/cli/ts-4-9/Header.stories.ts new file mode 100644 index 000000000000..b2f7d90ce371 --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/ts-4-9/Header.stories.ts @@ -0,0 +1,31 @@ +import type { Meta, StoryObj } from '@storybook/web-components-vite'; + +import { fn } from 'storybook/test'; + +import type { HeaderProps } from './Header'; +import { Header } from './Header'; + +const meta = { + title: 'Example/Header', + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + render: (args: HeaderProps) => Header(args), + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut: Story = {}; diff --git a/code/frameworks/web-components-vite/template/cli/ts-4-9/Header.ts b/code/frameworks/web-components-vite/template/cli/ts-4-9/Header.ts new file mode 100644 index 000000000000..7c3c8b89375a --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/ts-4-9/Header.ts @@ -0,0 +1,56 @@ +import { html } from 'lit'; + +import { Button } from './Button'; +import './header.css'; + +type User = { + name: string; +}; + +export interface HeaderProps { + user?: User; + onLogin?: () => void; + onLogout?: () => void; + onCreateAccount?: () => void; +} + +export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => html` +
+
+
+ + + + + + + +

Acme

+
+
+ ${user + ? Button({ size: 'small', onClick: onLogout, label: 'Log out' }) + : html`${Button({ + size: 'small', + onClick: onLogin, + label: 'Log in', + })} + ${Button({ + primary: true, + size: 'small', + onClick: onCreateAccount, + label: 'Sign up', + })}`} +
+
+
+`; diff --git a/code/frameworks/web-components-vite/template/cli/ts-4-9/Page.stories.ts b/code/frameworks/web-components-vite/template/cli/ts-4-9/Page.stories.ts new file mode 100644 index 000000000000..57505c5f694d --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/ts-4-9/Page.stories.ts @@ -0,0 +1,26 @@ +import type { Meta, StoryObj } from '@storybook/web-components-vite'; + +import * as HeaderStories from './Header.stories'; +import type { PageProps } from './Page'; +import { Page } from './Page'; + +const meta = { + title: 'Example/Page', + render: (args: PageProps) => Page(args), +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { + // More on composing args: https://storybook.js.org/docs/writing-stories/args#args-composition + ...HeaderStories.LoggedIn.args, + }, +}; + +export const LoggedOut: Story = { + args: { + ...HeaderStories.LoggedOut.args, + }, +}; diff --git a/code/frameworks/web-components-vite/template/cli/ts-4-9/Page.ts b/code/frameworks/web-components-vite/template/cli/ts-4-9/Page.ts new file mode 100644 index 000000000000..079c4f04cfbc --- /dev/null +++ b/code/frameworks/web-components-vite/template/cli/ts-4-9/Page.ts @@ -0,0 +1,73 @@ +import { html } from 'lit'; + +import { Header } from './Header'; +import './page.css'; + +type User = { + name: string; +}; + +export interface PageProps { + user?: User; + onLogin?: () => void; + onLogout?: () => void; + onCreateAccount?: () => void; +} + +export const Page = ({ user, onLogin, onLogout, onCreateAccount }: PageProps) => html` +
+ ${Header({ + user, + onLogin, + onLogout, + onCreateAccount, + })} + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
+`; diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index f7a59969d419..e13ae030089a 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -46,6 +46,7 @@ "types": "dist/index.d.ts", "files": [ "dist/**/*", + "template/**/*", "README.md", "*.js", "*.d.ts", diff --git a/code/frameworks/web-components-webpack5/src/index.ts b/code/frameworks/web-components-webpack5/src/index.ts index fcb073fefcd6..538d3b3a6d67 100644 --- a/code/frameworks/web-components-webpack5/src/index.ts +++ b/code/frameworks/web-components-webpack5/src/index.ts @@ -1 +1,2 @@ +export * from '@storybook/web-components'; export * from './types'; diff --git a/code/frameworks/web-components-webpack5/template/cli/.eslintrc.json b/code/frameworks/web-components-webpack5/template/cli/.eslintrc.json new file mode 100644 index 000000000000..40ece4a0aa18 --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "import/extensions": "off" + } +} diff --git a/code/frameworks/web-components-webpack5/template/cli/js/Button.js b/code/frameworks/web-components-webpack5/template/cli/js/Button.js new file mode 100644 index 000000000000..6cbe804eb1b7 --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/js/Button.js @@ -0,0 +1,20 @@ +import { html } from 'lit'; +import { styleMap } from 'lit/directives/style-map.js'; + +import './button.css'; + +/** Primary UI component for user interaction */ +export const Button = ({ primary, backgroundColor = null, size, label, onClick }) => { + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + + return html` + + `; +}; diff --git a/code/frameworks/web-components-webpack5/template/cli/js/Button.stories.js b/code/frameworks/web-components-webpack5/template/cli/js/Button.stories.js new file mode 100644 index 000000000000..9efdf07ece3d --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/js/Button.stories.js @@ -0,0 +1,46 @@ +import { fn } from 'storybook/test'; + +import { Button } from './Button'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +export default { + title: 'Example/Button', + tags: ['autodocs'], + render: (args) => Button(args), + argTypes: { + backgroundColor: { control: 'color' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + }, + }, + args: { onClick: fn() }, +}; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary = { + args: { + label: 'Button', + }, +}; + +export const Large = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/web-components-webpack5/template/cli/js/Header.js b/code/frameworks/web-components-webpack5/template/cli/js/Header.js new file mode 100644 index 000000000000..19fea63604a8 --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/js/Header.js @@ -0,0 +1,45 @@ +import { html } from 'lit'; + +import { Button } from './Button'; +import './header.css'; + +export const Header = ({ user, onLogin, onLogout, onCreateAccount }) => html` +
+
+
+ + + + + + + +

Acme

+
+
+ ${user + ? Button({ size: 'small', onClick: onLogout, label: 'Log out' }) + : html`${Button({ + size: 'small', + onClick: onLogin, + label: 'Log in', + })} + ${Button({ + primary: true, + size: 'small', + onClick: onCreateAccount, + label: 'Sign up', + })}`} +
+
+
+`; diff --git a/code/frameworks/web-components-webpack5/template/cli/js/Header.stories.js b/code/frameworks/web-components-webpack5/template/cli/js/Header.stories.js new file mode 100644 index 000000000000..b45ba68c5a87 --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/js/Header.stories.js @@ -0,0 +1,24 @@ +import { fn } from 'storybook/test'; + +import { Header } from './Header'; + +export default { + title: 'Example/Header', + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/web-components/vue/writing-docs/autodocs + tags: ['autodocs'], + render: (args) => Header(args), + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, +}; +export const LoggedIn = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut = {}; diff --git a/code/frameworks/web-components-webpack5/template/cli/js/Page.js b/code/frameworks/web-components-webpack5/template/cli/js/Page.js new file mode 100644 index 000000000000..54919dabd48b --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/js/Page.js @@ -0,0 +1,62 @@ +import { html } from 'lit'; + +import { Header } from './Header'; +import './page.css'; + +export const Page = ({ user, onLogin, onLogout, onCreateAccount }) => html` +
+ ${Header({ + user, + onLogin, + onLogout, + onCreateAccount, + })} + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
+`; diff --git a/code/frameworks/web-components-webpack5/template/cli/js/Page.stories.js b/code/frameworks/web-components-webpack5/template/cli/js/Page.stories.js new file mode 100644 index 000000000000..7c28c5ad14b3 --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/js/Page.stories.js @@ -0,0 +1,20 @@ +import * as HeaderStories from './Header.stories'; +import { Page } from './Page'; + +export default { + title: 'Example/Page', + render: (args) => Page(args), +}; + +export const LoggedIn = { + args: { + // More on composing args: https://storybook.js.org/docs/writing-stories/args#args-composition + ...HeaderStories.LoggedIn.args, + }, +}; + +export const LoggedOut = { + args: { + ...HeaderStories.LoggedOut.args, + }, +}; diff --git a/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Button.stories.ts b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Button.stories.ts new file mode 100644 index 000000000000..e3085252e4bb --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Button.stories.ts @@ -0,0 +1,52 @@ +import type { Meta, StoryObj } from '@storybook/web-components-webpack5'; + +import { fn } from 'storybook/test'; + +import type { ButtonProps } from './Button'; +import { Button } from './Button'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories +const meta = { + title: 'Example/Button', + tags: ['autodocs'], + render: (args) => Button(args), + argTypes: { + backgroundColor: { control: 'color' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + }, + }, + args: { onClick: fn() }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary: Story = { + args: { + primary: true, + label: 'Button', + }, +}; + +export const Secondary: Story = { + args: { + label: 'Button', + }, +}; + +export const Large: Story = { + args: { + size: 'large', + label: 'Button', + }, +}; + +export const Small: Story = { + args: { + size: 'small', + label: 'Button', + }, +}; diff --git a/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Button.ts b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Button.ts new file mode 100644 index 000000000000..4ca7fe4a7232 --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Button.ts @@ -0,0 +1,32 @@ +import { html } from 'lit'; +import { styleMap } from 'lit/directives/style-map.js'; + +import './button.css'; + +export interface ButtonProps { + /** Is this the principal call to action on the page? */ + primary?: boolean; + /** What background color to use */ + backgroundColor?: string; + /** How large should the button be? */ + size?: 'small' | 'medium' | 'large'; + /** Button contents */ + label: string; + /** Optional click handler */ + onClick?: () => void; +} +/** Primary UI component for user interaction */ +export const Button = ({ primary, backgroundColor, size, label, onClick }: ButtonProps) => { + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + + return html` + + `; +}; diff --git a/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Header.stories.ts b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Header.stories.ts new file mode 100644 index 000000000000..9564aa90e730 --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Header.stories.ts @@ -0,0 +1,31 @@ +import type { Meta, StoryObj } from '@storybook/web-components-webpack5'; + +import { fn } from 'storybook/test'; + +import type { HeaderProps } from './Header'; +import { Header } from './Header'; + +const meta = { + title: 'Example/Header', + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + render: (args: HeaderProps) => Header(args), + args: { + onLogin: fn(), + onLogout: fn(), + onCreateAccount: fn(), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { + user: { + name: 'Jane Doe', + }, + }, +}; + +export const LoggedOut: Story = {}; diff --git a/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Header.ts b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Header.ts new file mode 100644 index 000000000000..7c3c8b89375a --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Header.ts @@ -0,0 +1,56 @@ +import { html } from 'lit'; + +import { Button } from './Button'; +import './header.css'; + +type User = { + name: string; +}; + +export interface HeaderProps { + user?: User; + onLogin?: () => void; + onLogout?: () => void; + onCreateAccount?: () => void; +} + +export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => html` +
+
+
+ + + + + + + +

Acme

+
+
+ ${user + ? Button({ size: 'small', onClick: onLogout, label: 'Log out' }) + : html`${Button({ + size: 'small', + onClick: onLogin, + label: 'Log in', + })} + ${Button({ + primary: true, + size: 'small', + onClick: onCreateAccount, + label: 'Sign up', + })}`} +
+
+
+`; diff --git a/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Page.stories.ts b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Page.stories.ts new file mode 100644 index 000000000000..51ba30dfaaea --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Page.stories.ts @@ -0,0 +1,26 @@ +import type { Meta, StoryObj } from '@storybook/web-components-webpack5'; + +import * as HeaderStories from './Header.stories'; +import type { PageProps } from './Page'; +import { Page } from './Page'; + +const meta = { + title: 'Example/Page', + render: (args: PageProps) => Page(args), +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { + // More on composing args: https://storybook.js.org/docs/writing-stories/args#args-composition + ...HeaderStories.LoggedIn.args, + }, +}; + +export const LoggedOut: Story = { + args: { + ...HeaderStories.LoggedOut.args, + }, +}; diff --git a/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Page.ts b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Page.ts new file mode 100644 index 000000000000..079c4f04cfbc --- /dev/null +++ b/code/frameworks/web-components-webpack5/template/cli/ts-4-9/Page.ts @@ -0,0 +1,73 @@ +import { html } from 'lit'; + +import { Header } from './Header'; +import './page.css'; + +type User = { + name: string; +}; + +export interface PageProps { + user?: User; + onLogin?: () => void; + onLogout?: () => void; + onCreateAccount?: () => void; +} + +export const Page = ({ user, onLogin, onLogout, onCreateAccount }: PageProps) => html` +
+ ${Header({ + user, + onLogin, + onLogout, + onCreateAccount, + })} + +
+

Pages in Storybook

+

+ We recommend building UIs with a + + component-driven process starting with atomic components and ending with pages. +

+

+ Render pages with mock data. This makes it easy to build and review page states without + needing to navigate to them in your app. Here are some handy patterns for managing page data + in Storybook: +

+
    +
  • + Use a higher-level connected component. Storybook helps you compose such data from the + "args" of child component stories +
  • +
  • + Assemble data in the page component from your services. You can mock these services out + using Storybook. +
  • +
+

+ Get a guided tutorial on component-driven development at + + Storybook tutorials + + . Read more in the + docs + . +

+
+ Tip Adjust the width of the canvas with the + + + + + + Viewports addon in the toolbar +
+
+
+`; diff --git a/code/lib/blocks/package.json b/code/lib/blocks/package.json index a124f721788b..c8bd492d8868 100644 --- a/code/lib/blocks/package.json +++ b/code/lib/blocks/package.json @@ -49,7 +49,6 @@ "devDependencies": { "@storybook/addon-actions": "workspace:*", "@storybook/react": "workspace:*", - "@storybook/test": "workspace:*", "@types/color-convert": "^2.0.0", "color-convert": "^2.0.1", "es-toolkit": "^1.22.0", diff --git a/code/lib/blocks/src/blocks/Anchor.stories.tsx b/code/lib/blocks/src/blocks/Anchor.stories.tsx index 276c5aa2219e..262af3d77039 100644 --- a/code/lib/blocks/src/blocks/Anchor.stories.tsx +++ b/code/lib/blocks/src/blocks/Anchor.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Anchor } from './Anchor'; diff --git a/code/lib/blocks/src/blocks/ArgTypes.stories.tsx b/code/lib/blocks/src/blocks/ArgTypes.stories.tsx index 7738bde257eb..4a17e355d874 100644 --- a/code/lib/blocks/src/blocks/ArgTypes.stories.tsx +++ b/code/lib/blocks/src/blocks/ArgTypes.stories.tsx @@ -2,8 +2,9 @@ import React from 'react'; import type { PlayFunctionContext } from 'storybook/internal/csf'; -import type { Meta, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { within } from 'storybook/test'; import * as ExampleStories from '../examples/ArgTypesParameters.stories'; import * as SubcomponentsExampleStories from '../examples/ArgTypesWithSubcomponentsParameters.stories'; diff --git a/code/lib/blocks/src/blocks/Canvas.stories.tsx b/code/lib/blocks/src/blocks/Canvas.stories.tsx index 987e28678a71..befddeebd0ad 100644 --- a/code/lib/blocks/src/blocks/Canvas.stories.tsx +++ b/code/lib/blocks/src/blocks/Canvas.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { dedent } from 'ts-dedent'; diff --git a/code/lib/blocks/src/blocks/Controls.stories.tsx b/code/lib/blocks/src/blocks/Controls.stories.tsx index 624f03452b8b..09e424484c55 100644 --- a/code/lib/blocks/src/blocks/Controls.stories.tsx +++ b/code/lib/blocks/src/blocks/Controls.stories.tsx @@ -2,8 +2,9 @@ import React from 'react'; import type { PlayFunctionContext } from 'storybook/internal/csf'; -import type { Meta, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { within } from 'storybook/test'; import * as ExampleStories from '../examples/ControlsParameters.stories'; import * as SubcomponentsExampleStories from '../examples/ControlsWithSubcomponentsParameters.stories'; diff --git a/code/lib/blocks/src/blocks/Description.stories.tsx b/code/lib/blocks/src/blocks/Description.stories.tsx index 9285fd9095ff..31bbea234588 100644 --- a/code/lib/blocks/src/blocks/Description.stories.tsx +++ b/code/lib/blocks/src/blocks/Description.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button as ButtonComponent } from '../examples/Button'; import * as DefaultButtonStories from '../examples/Button.stories'; diff --git a/code/lib/blocks/src/blocks/DocsPage.stories.tsx b/code/lib/blocks/src/blocks/DocsPage.stories.tsx index 1ed85bfa3ac9..31b433f68867 100644 --- a/code/lib/blocks/src/blocks/DocsPage.stories.tsx +++ b/code/lib/blocks/src/blocks/DocsPage.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { DocsPage } from './DocsPage'; diff --git a/code/lib/blocks/src/blocks/Primary.stories.tsx b/code/lib/blocks/src/blocks/Primary.stories.tsx index 6ea9025eac9c..39b9123ea726 100644 --- a/code/lib/blocks/src/blocks/Primary.stories.tsx +++ b/code/lib/blocks/src/blocks/Primary.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import * as DefaultButtonStories from '../examples/Button.stories'; import * as StoriesParametersStories from '../examples/StoriesParameters.stories'; diff --git a/code/lib/blocks/src/blocks/Source.stories.tsx b/code/lib/blocks/src/blocks/Source.stories.tsx index 8981289a1491..30915ce18af9 100644 --- a/code/lib/blocks/src/blocks/Source.stories.tsx +++ b/code/lib/blocks/src/blocks/Source.stories.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { SourceType } from 'storybook/internal/docs-tools'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { dedent } from 'ts-dedent'; diff --git a/code/lib/blocks/src/blocks/Stories.stories.tsx b/code/lib/blocks/src/blocks/Stories.stories.tsx index 017da21c799e..98576f0892b6 100644 --- a/code/lib/blocks/src/blocks/Stories.stories.tsx +++ b/code/lib/blocks/src/blocks/Stories.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Stories } from './Stories'; diff --git a/code/lib/blocks/src/blocks/Story.stories.tsx b/code/lib/blocks/src/blocks/Story.stories.tsx index 370262bf0f2f..6616b489934e 100644 --- a/code/lib/blocks/src/blocks/Story.stories.tsx +++ b/code/lib/blocks/src/blocks/Story.stories.tsx @@ -1,7 +1,8 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, waitFor } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, waitFor } from 'storybook/test'; import * as StoryComponentStories from '../components/Story.stories'; import * as ButtonStories from '../examples/Button.stories'; diff --git a/code/lib/blocks/src/blocks/Subtitle.stories.tsx b/code/lib/blocks/src/blocks/Subtitle.stories.tsx index df1b8ff2fd70..e0e847cd9182 100644 --- a/code/lib/blocks/src/blocks/Subtitle.stories.tsx +++ b/code/lib/blocks/src/blocks/Subtitle.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import * as DefaultButtonStories from '../examples/Button.stories'; import * as ButtonStoriesWithMetaSubtitleAsBoth from '../examples/ButtonWithMetaSubtitleAsBoth.stories'; diff --git a/code/lib/blocks/src/blocks/Title.stories.tsx b/code/lib/blocks/src/blocks/Title.stories.tsx index 00ec452971be..7eed0521a0a2 100644 --- a/code/lib/blocks/src/blocks/Title.stories.tsx +++ b/code/lib/blocks/src/blocks/Title.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import * as DefaultButtonStories from '../examples/Button.stories'; import { Title } from './Title'; diff --git a/code/lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx b/code/lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx index ce83ae7e67ed..3cbad6a0e329 100644 --- a/code/lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx +++ b/code/lib/blocks/src/components/ArgsTable/ArgsTable.stories.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { styled } from 'storybook/internal/theming'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { action } from '@storybook/addon-actions'; diff --git a/code/lib/blocks/src/components/Source.stories.tsx b/code/lib/blocks/src/components/Source.stories.tsx index d7028b920e05..cd2d7ae38bb9 100644 --- a/code/lib/blocks/src/components/Source.stories.tsx +++ b/code/lib/blocks/src/components/Source.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Source, SourceError } from './Source'; diff --git a/code/lib/blocks/src/components/Story.stories.tsx b/code/lib/blocks/src/components/Story.stories.tsx index 09e64a2dd1dd..9d3ad8c7591b 100644 --- a/code/lib/blocks/src/components/Story.stories.tsx +++ b/code/lib/blocks/src/components/Story.stories.tsx @@ -10,8 +10,9 @@ import type { PlayFunctionContext } from 'storybook/internal/csf'; import type { PreviewWeb } from 'storybook/internal/preview-api'; import type { ModuleExport, WebRenderer } from 'storybook/internal/types'; -import type { Meta, ReactRenderer, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; +import type { Meta, ReactRenderer, StoryObj } from '@storybook/react-vite'; + +import { within } from 'storybook/test'; import type { DocsContextProps } from '../blocks'; import * as ButtonStories from '../examples/Button.stories'; diff --git a/code/lib/blocks/src/controls/Boolean.stories.tsx b/code/lib/blocks/src/controls/Boolean.stories.tsx index ad7365c03838..5276f71edb6e 100644 --- a/code/lib/blocks/src/controls/Boolean.stories.tsx +++ b/code/lib/blocks/src/controls/Boolean.stories.tsx @@ -1,8 +1,9 @@ import { RESET_STORY_ARGS, STORY_ARGS_UPDATED } from 'storybook/internal/core-events'; import { addons } from 'storybook/internal/preview-api'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fireEvent, fn, waitFor, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, fireEvent, fn, waitFor, within } from 'storybook/test'; import { BooleanControl } from './Boolean'; diff --git a/code/lib/blocks/src/controls/Color.stories.tsx b/code/lib/blocks/src/controls/Color.stories.tsx index 8b77cff62f0c..867e0d0c5cb7 100644 --- a/code/lib/blocks/src/controls/Color.stories.tsx +++ b/code/lib/blocks/src/controls/Color.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { ColorControl } from './Color'; diff --git a/code/lib/blocks/src/controls/Date.stories.tsx b/code/lib/blocks/src/controls/Date.stories.tsx index c2fcb33e39bb..f8f3200f3129 100644 --- a/code/lib/blocks/src/controls/Date.stories.tsx +++ b/code/lib/blocks/src/controls/Date.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { DateControl } from './Date'; diff --git a/code/lib/blocks/src/controls/Files.stories.tsx b/code/lib/blocks/src/controls/Files.stories.tsx index 640f954260c1..82c8f61eed1e 100644 --- a/code/lib/blocks/src/controls/Files.stories.tsx +++ b/code/lib/blocks/src/controls/Files.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { FilesControl } from './Files'; diff --git a/code/lib/blocks/src/controls/Number.stories.tsx b/code/lib/blocks/src/controls/Number.stories.tsx index 80bde03aeeff..ae5daf07be0d 100644 --- a/code/lib/blocks/src/controls/Number.stories.tsx +++ b/code/lib/blocks/src/controls/Number.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { NumberControl } from './Number'; diff --git a/code/lib/blocks/src/controls/Object.stories.tsx b/code/lib/blocks/src/controls/Object.stories.tsx index 0929234e3ad2..de883570198b 100644 --- a/code/lib/blocks/src/controls/Object.stories.tsx +++ b/code/lib/blocks/src/controls/Object.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { ObjectControl } from './Object'; diff --git a/code/lib/blocks/src/controls/Range.stories.tsx b/code/lib/blocks/src/controls/Range.stories.tsx index cd8ca20c5220..b8464d923c17 100644 --- a/code/lib/blocks/src/controls/Range.stories.tsx +++ b/code/lib/blocks/src/controls/Range.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { RangeControl } from './Range'; diff --git a/code/lib/blocks/src/controls/Text.stories.tsx b/code/lib/blocks/src/controls/Text.stories.tsx index 71dee59dc19a..e1ce009699f2 100644 --- a/code/lib/blocks/src/controls/Text.stories.tsx +++ b/code/lib/blocks/src/controls/Text.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { TextControl } from './Text'; diff --git a/code/lib/blocks/src/controls/options/CheckOptions.stories.tsx b/code/lib/blocks/src/controls/options/CheckOptions.stories.tsx index 8e98d88c080f..e98ac3cc049e 100644 --- a/code/lib/blocks/src/controls/options/CheckOptions.stories.tsx +++ b/code/lib/blocks/src/controls/options/CheckOptions.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { OptionsControl } from './Options'; diff --git a/code/lib/blocks/src/controls/options/RadioOptions.stories.tsx b/code/lib/blocks/src/controls/options/RadioOptions.stories.tsx index e96f52b781cf..e0a5bb706a4e 100644 --- a/code/lib/blocks/src/controls/options/RadioOptions.stories.tsx +++ b/code/lib/blocks/src/controls/options/RadioOptions.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { OptionsControl } from './Options'; diff --git a/code/lib/blocks/src/controls/options/SelectOptions.stories.tsx b/code/lib/blocks/src/controls/options/SelectOptions.stories.tsx index 81efc451c7f5..71e28da394d4 100644 --- a/code/lib/blocks/src/controls/options/SelectOptions.stories.tsx +++ b/code/lib/blocks/src/controls/options/SelectOptions.stories.tsx @@ -1,5 +1,6 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { fn } from 'storybook/test'; import { OptionsControl } from './Options'; diff --git a/code/lib/blocks/src/examples/ArgTypesParameters.stories.tsx b/code/lib/blocks/src/examples/ArgTypesParameters.stories.tsx index 95fef9f585fc..a5660dbfd967 100644 --- a/code/lib/blocks/src/examples/ArgTypesParameters.stories.tsx +++ b/code/lib/blocks/src/examples/ArgTypesParameters.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { ArgTypesParameters } from './ArgTypesParameters'; diff --git a/code/lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx b/code/lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx index b6c66a4ae53a..24b00efc25d2 100644 --- a/code/lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx +++ b/code/lib/blocks/src/examples/ArgTypesWithSubcomponentsParameters.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { ArgTypesParameters, SubcomponentA, SubcomponentB } from './ArgTypesParameters'; diff --git a/code/lib/blocks/src/examples/Button.stories.tsx b/code/lib/blocks/src/examples/Button.stories.tsx index c22d141f541c..8aa24f8a8ed9 100644 --- a/code/lib/blocks/src/examples/Button.stories.tsx +++ b/code/lib/blocks/src/examples/Button.stories.tsx @@ -1,8 +1,9 @@ /* eslint-disable local-rules/no-uncategorized-errors */ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, fireEvent, within } from '@storybook/test'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { expect, fireEvent, within } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/ButtonNoAutodocs.stories.tsx b/code/lib/blocks/src/examples/ButtonNoAutodocs.stories.tsx index 727ba4598ba2..ac771a2c43d3 100644 --- a/code/lib/blocks/src/examples/ButtonNoAutodocs.stories.tsx +++ b/code/lib/blocks/src/examples/ButtonNoAutodocs.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/ButtonReadonly.stories.tsx b/code/lib/blocks/src/examples/ButtonReadonly.stories.tsx index 442f945490b2..7fc7bffe26b5 100644 --- a/code/lib/blocks/src/examples/ButtonReadonly.stories.tsx +++ b/code/lib/blocks/src/examples/ButtonReadonly.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/ButtonSomeAutodocs.stories.tsx b/code/lib/blocks/src/examples/ButtonSomeAutodocs.stories.tsx index fbc06945b979..62e7c8c37210 100644 --- a/code/lib/blocks/src/examples/ButtonSomeAutodocs.stories.tsx +++ b/code/lib/blocks/src/examples/ButtonSomeAutodocs.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx b/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx index a5515b3ee335..40543373c6ef 100644 --- a/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx +++ b/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx b/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx index 95464610b4aa..31862be623d2 100644 --- a/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx +++ b/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsComment.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx b/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx index fff71f67e626..bf044d45bac6 100644 --- a/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx +++ b/code/lib/blocks/src/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx b/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx index 6ee3c6c12930..78f6218743ba 100644 --- a/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx +++ b/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx b/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx index 9a430f39e81f..f67f7c5aeaef 100644 --- a/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx +++ b/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx b/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx index 0ec5ff64c6fe..47794cda9006 100644 --- a/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx +++ b/code/lib/blocks/src/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { Button } from './Button'; diff --git a/code/lib/blocks/src/examples/CanvasParameters.stories.tsx b/code/lib/blocks/src/examples/CanvasParameters.stories.tsx index 4d4433747494..c286e07e7bbc 100644 --- a/code/lib/blocks/src/examples/CanvasParameters.stories.tsx +++ b/code/lib/blocks/src/examples/CanvasParameters.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { EmptyExample } from './EmptyExample'; diff --git a/code/lib/blocks/src/examples/ControlsParameters.stories.tsx b/code/lib/blocks/src/examples/ControlsParameters.stories.tsx index 7684d4f0e02f..497c543d728c 100644 --- a/code/lib/blocks/src/examples/ControlsParameters.stories.tsx +++ b/code/lib/blocks/src/examples/ControlsParameters.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { ControlsParameters } from './ControlsParameters'; diff --git a/code/lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx b/code/lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx index bf2e1e77d37a..543c55be5546 100644 --- a/code/lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx +++ b/code/lib/blocks/src/examples/ControlsWithSubcomponentsParameters.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { ControlsParameters, SubcomponentA, SubcomponentB } from './ControlsParameters'; diff --git a/code/lib/blocks/src/examples/DocsPageParameters.stories.tsx b/code/lib/blocks/src/examples/DocsPageParameters.stories.tsx index 91d5b3f3cadd..2f52462c6e7c 100644 --- a/code/lib/blocks/src/examples/DocsPageParameters.stories.tsx +++ b/code/lib/blocks/src/examples/DocsPageParameters.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { EmptyExample } from './EmptyExample'; diff --git a/code/lib/blocks/src/examples/EmptyArgTypes.stories.tsx b/code/lib/blocks/src/examples/EmptyArgTypes.stories.tsx index 9c596e5def69..ebe717ad91d9 100644 --- a/code/lib/blocks/src/examples/EmptyArgTypes.stories.tsx +++ b/code/lib/blocks/src/examples/EmptyArgTypes.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import type { ControlsParameters } from './ControlsParameters'; diff --git a/code/lib/blocks/src/examples/SourceParameters.stories.tsx b/code/lib/blocks/src/examples/SourceParameters.stories.tsx index ee40704a051e..cc1043678228 100644 --- a/code/lib/blocks/src/examples/SourceParameters.stories.tsx +++ b/code/lib/blocks/src/examples/SourceParameters.stories.tsx @@ -1,7 +1,7 @@ import { SourceType } from 'storybook/internal/docs-tools'; import type { StoryContext } from 'storybook/internal/types'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { dedent } from 'ts-dedent'; diff --git a/code/lib/blocks/src/examples/StoriesParameters.stories.tsx b/code/lib/blocks/src/examples/StoriesParameters.stories.tsx index 731291ad75f7..74b397ee4b69 100644 --- a/code/lib/blocks/src/examples/StoriesParameters.stories.tsx +++ b/code/lib/blocks/src/examples/StoriesParameters.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { EmptyExample } from './EmptyExample'; diff --git a/code/lib/blocks/src/examples/StoryParameters.stories.tsx b/code/lib/blocks/src/examples/StoryParameters.stories.tsx index 79c8dcb7bdca..2280656b0b45 100644 --- a/code/lib/blocks/src/examples/StoryParameters.stories.tsx +++ b/code/lib/blocks/src/examples/StoryParameters.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { SimpleSizeTest } from './SimpleSizeTest'; diff --git a/code/lib/cli-storybook/src/autoblock/block-storystorev6.ts b/code/lib/cli-storybook/src/autoblock/block-storystorev6.ts index 9d28b8d15a08..83cff982ef96 100644 --- a/code/lib/cli-storybook/src/autoblock/block-storystorev6.ts +++ b/code/lib/cli-storybook/src/autoblock/block-storystorev6.ts @@ -28,7 +28,7 @@ export const blocker = createBlocker({ In your Storybook configuration we found storyStoreV7 feature defined. For instance: - export default = { + export default { features: { ${picocolors.cyan(`storyStoreV7: false`)}, <--- ${picocolors.bold('remove this line')} }, diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.ts index 41d58bc46a7c..d54bd76733ae 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.ts @@ -8,7 +8,7 @@ import path from 'path'; import picocolors from 'picocolors'; import { dedent } from 'ts-dedent'; -// Relative path import to avoid dependency to @storybook/test +// Relative path import to avoid dependency to storybook/test import { SUPPORTED_FRAMEWORKS, SUPPORTED_RENDERERS, diff --git a/code/lib/cli-storybook/src/automigrate/fixes/consolidated-imports.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/consolidated-imports.test.ts new file mode 100644 index 000000000000..a7f0c5cbee47 --- /dev/null +++ b/code/lib/cli-storybook/src/automigrate/fixes/consolidated-imports.test.ts @@ -0,0 +1,298 @@ +import { readFile, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; + +import { describe, expect, it, vi } from 'vitest'; + +import { dedent } from 'ts-dedent'; + +import { + consolidatedImports, + transformImportFiles, + transformPackageJsonFiles, +} from './consolidated-imports'; + +vi.mock('node:fs/promises'); +vi.mock('globby', () => ({ + globby: vi.fn(), +})); + +const mockPackageJson = { + dependencies: { + '@storybook/react': '^7.0.0', + '@storybook/core-common': '^7.0.0', + react: '^18.0.0', + }, + devDependencies: { + '@storybook/addon-essentials': '^7.0.0', + '@storybook/manager-api': '^7.0.0', + typescript: '^5.0.0', + }, +}; + +const mockRunOptions = { + packageManager: { + retrievePackageJson: async () => mockPackageJson, + } as any, + mainConfig: {} as any, + mainConfigPath: 'main.ts', + packageJson: mockPackageJson, +}; + +const setupGlobby = async (files: string[]) => { + // eslint-disable-next-line depend/ban-dependencies + const { globby } = await import('globby'); + vi.mocked(globby).mockResolvedValueOnce(files); +}; + +const setupCheck = async (packageJsonContents: string, packageJsonFiles: string[]) => { + vi.mocked(readFile).mockImplementation(async (path: any) => { + const filePath = path.toString(); + if (filePath.endsWith('package.json')) { + return packageJsonContents; + } + return ''; + }); + await setupGlobby(packageJsonFiles); + + return consolidatedImports.check({ + ...mockRunOptions, + storybookVersion: '8.0.0', + }); +}; + +describe('check', () => { + it('should call globby with correct patterns for package.json files', async () => { + const filePath = 'test/package.json'; + const contents = JSON.stringify(mockPackageJson); + + await setupCheck(contents, [filePath]); + + // eslint-disable-next-line depend/ban-dependencies + const { globby } = await import('globby'); + expect(globby).toHaveBeenCalledWith( + ['**/package.json'], + expect.objectContaining({ + ignore: ['**/node_modules/**'], + }) + ); + }); + + it('should detect consolidated packages in package.json', async () => { + const contents = JSON.stringify(mockPackageJson); + const filePath = 'test/package.json'; + + const result = await setupCheck(contents, [filePath]); + expect(result).toMatchObject({ + packageJsonFiles: [filePath], + }); + }); + + it('should not detect non-consolidated packages in package.json', async () => { + const packageJsonWithoutConsolidated = { + dependencies: { + react: '^18.0.0', + }, + devDependencies: { + typescript: '^5.0.0', + }, + }; + const contents = JSON.stringify(packageJsonWithoutConsolidated); + const filePath = 'test/package.json'; + + const result = await setupCheck(contents, [filePath]); + expect(result).toBeNull(); + }); +}); + +describe('transformPackageJsonFiles', () => { + it('should transform package.json files', async () => { + const contents = JSON.stringify(mockPackageJson); + const filePath = 'test/package.json'; + + vi.mocked(readFile).mockResolvedValueOnce(contents); + + const errors = await transformPackageJsonFiles([filePath], false); + + expect(errors).toHaveLength(0); + expect(writeFile).toHaveBeenCalledWith( + filePath, + expect.not.stringContaining('"@storybook/core-common": "^8.0.0"') + ); + }); + + it('should not write files in dry run mode', async () => { + const contents = JSON.stringify(mockPackageJson); + const filePath = 'test/package.json'; + + vi.mocked(readFile).mockResolvedValueOnce(contents); + + const errors = await transformPackageJsonFiles([filePath], true); + + expect(errors).toHaveLength(0); + expect(writeFile).not.toHaveBeenCalled(); + }); + + it('should handle file read errors', async () => { + const filePath = 'test/package.json'; + vi.mocked(readFile).mockRejectedValueOnce(new Error('Failed to read file')); + + const errors = await transformPackageJsonFiles([filePath], false); + + expect(errors).toHaveLength(1); + expect(errors[0]).toMatchObject({ + file: filePath, + error: expect.any(Error), + }); + }); + + it('should handle file write errors', async () => { + const contents = JSON.stringify(mockPackageJson); + const filePath = 'test/package.json'; + vi.mocked(readFile).mockResolvedValueOnce(contents); + vi.mocked(writeFile).mockRejectedValueOnce(new Error('Failed to write file')); + + const errors = await transformPackageJsonFiles([filePath], false); + + expect(errors).toHaveLength(1); + expect(errors[0]).toMatchObject({ + file: filePath, + error: expect.any(Error), + }); + }); +}); + +describe('transformImportFiles', () => { + it('should transform import declarations', async () => { + const sourceContents = dedent` + import { something } from '@storybook/components'; + import { other } from '@storybook/core-common'; + `; + const sourceFiles = [join('src', 'test.ts')]; + + vi.mocked(readFile).mockResolvedValueOnce(sourceContents); + + const errors = await transformImportFiles(sourceFiles, false); + + expect(errors).toHaveLength(0); + expect(writeFile).toHaveBeenCalledWith( + sourceFiles[0], + expect.stringContaining(`from 'storybook/internal/components'`) + ); + }); + + it('should transform import declarations with sub-paths', async () => { + const sourceContents = dedent` + import { other } from '@storybook/theming/create'; + `; + const sourceFiles = [join('src', 'test.ts')]; + + vi.mocked(readFile).mockResolvedValueOnce(sourceContents); + + const errors = await transformImportFiles(sourceFiles, false); + + expect(errors).toHaveLength(0); + expect(writeFile).toHaveBeenCalledWith( + sourceFiles[0], + expect.stringContaining(`from 'storybook/internal/theming/create'`) + ); + }); + + it('should transform require calls', async () => { + const sourceContents = dedent` + const something = require('@storybook/components'); + const other = require('@storybook/core-common'); + `; + const sourceFiles = [join('src', 'test.ts')]; + + vi.mocked(readFile).mockResolvedValueOnce(sourceContents); + + const errors = await transformImportFiles(sourceFiles, false); + + expect(errors).toHaveLength(0); + expect(writeFile).toHaveBeenCalledWith( + sourceFiles[0], + expect.stringContaining(`require('storybook/internal/components')`) + ); + }); + + it('should handle mixed import styles', async () => { + const sourceContents = dedent` + import { something } from '@storybook/components'; + const other = require('@storybook/core-common'); + `; + const sourceFiles = [join('src', 'test.ts')]; + + vi.mocked(readFile).mockResolvedValueOnce(sourceContents); + + const errors = await transformImportFiles(sourceFiles, false); + + expect(errors).toHaveLength(0); + expect(writeFile).toHaveBeenCalledWith( + sourceFiles[0], + expect.stringContaining(`from 'storybook/internal/components'`) + ); + expect(writeFile).toHaveBeenCalledWith( + sourceFiles[0], + expect.stringContaining(`require('storybook/internal/common')`) + ); + }); + + it('should not transform non-consolidated package imports', async () => { + const sourceContents = ` + import { something } from '@storybook/other-package'; + const other = require('some-other-package'); + `; + const sourceFiles = [join('src', 'test.ts')]; + + vi.mocked(readFile).mockResolvedValueOnce(sourceContents); + + const errors = await transformImportFiles(sourceFiles, false); + + expect(errors).toHaveLength(0); + expect(writeFile).not.toHaveBeenCalledWith(sourceFiles[0], expect.any(String)); + }); + + it('should not write files in dry run mode', async () => { + const sourceContents = dedent` + import { something } from '@storybook/components'; + `; + const sourceFiles = [join('src', 'test.ts')]; + + vi.mocked(readFile).mockResolvedValueOnce(sourceContents); + + const errors = await transformImportFiles(sourceFiles, true); + + expect(errors).toHaveLength(0); + expect(writeFile).not.toHaveBeenCalled(); + }); + + it('should handle file read errors', async () => { + const sourceFiles = [join('src', 'test.ts')]; + vi.mocked(readFile).mockRejectedValueOnce(new Error('Failed to read file')); + + const errors = await transformImportFiles(sourceFiles, false); + + expect(errors).toHaveLength(1); + expect(errors[0]).toMatchObject({ + file: sourceFiles[0], + error: expect.any(Error), + }); + }); + + it('should handle file write errors', async () => { + const sourceContents = dedent` + import { something } from '@storybook/components'; + `; + const sourceFiles = [join('src', 'test.ts')]; + vi.mocked(readFile).mockResolvedValueOnce(sourceContents); + vi.mocked(writeFile).mockRejectedValueOnce(new Error('Failed to write file')); + + const errors = await transformImportFiles(sourceFiles, false); + + expect(errors).toHaveLength(1); + expect(errors[0]).toMatchObject({ + file: sourceFiles[0], + error: expect.any(Error), + }); + }); +}); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/consolidated-imports.ts b/code/lib/cli-storybook/src/automigrate/fixes/consolidated-imports.ts new file mode 100644 index 000000000000..103911b39967 --- /dev/null +++ b/code/lib/cli-storybook/src/automigrate/fixes/consolidated-imports.ts @@ -0,0 +1,203 @@ +import { readFile, writeFile } from 'node:fs/promises'; + +import { commonGlobOptions, getProjectRoot } from 'storybook/internal/common'; + +import prompts from 'prompts'; +import { dedent } from 'ts-dedent'; + +import { consolidatedPackages } from '../helpers/consolidated-packages'; +import type { Fix, RunOptions } from '../types'; + +export interface ConsolidatedOptions { + packageJsonFiles: string[]; +} + +function transformPackageJson(content: string): string | null { + const packageJson = JSON.parse(content); + let hasChanges = false; + + // Check dependencies + if (packageJson.dependencies) { + for (const [dep, version] of Object.entries(packageJson.dependencies)) { + if (dep in consolidatedPackages) { + delete packageJson.dependencies[dep]; + hasChanges = true; + } + } + } + + // Check devDependencies + if (packageJson.devDependencies) { + for (const [dep, version] of Object.entries(packageJson.devDependencies)) { + if (dep in consolidatedPackages) { + delete packageJson.devDependencies[dep]; + hasChanges = true; + } + } + } + + return hasChanges ? JSON.stringify(packageJson, null, 2) : null; +} + +function transformImports(source: string) { + let hasChanges = false; + let transformed = source; + + for (const [from, to] of Object.entries(consolidatedPackages)) { + // Match the package name when it's inside either single or double quotes + const regex = new RegExp(`(['"])${from}(.*)\\1`, 'g'); + if (regex.test(transformed)) { + transformed = transformed.replace(regex, `$1${to}$2$1`); + hasChanges = true; + } + } + + return hasChanges ? transformed : null; +} + +export const transformPackageJsonFiles = async (files: string[], dryRun: boolean) => { + const errors: Array<{ file: string; error: Error }> = []; + + const { default: pLimit } = await import('p-limit'); + + const limit = pLimit(10); + + await Promise.all( + files.map((file) => + limit(async () => { + try { + const contents = await readFile(file, 'utf-8'); + const transformed = transformPackageJson(contents); + if (!dryRun && transformed) { + await writeFile(file, transformed); + } + } catch (error) { + errors.push({ file, error: error as Error }); + } + }) + ) + ); + + return errors; +}; + +export const transformImportFiles = async (files: string[], dryRun: boolean) => { + const errors: Array<{ file: string; error: Error }> = []; + const { default: pLimit } = await import('p-limit'); + const limit = pLimit(10); + + await Promise.all( + files.map((file) => + limit(async () => { + try { + const contents = await readFile(file, 'utf-8'); + const transformed = transformImports(contents); + if (!dryRun && transformed) { + await writeFile(file, transformed); + } + } catch (error) { + errors.push({ file, error: error as Error }); + } + }) + ) + ); + + return errors; +}; + +export const consolidatedImports: Fix = { + id: 'consolidated-imports', + versionRange: ['^8.0.0', '^9.0.0-0'], + check: async () => { + const projectRoot = getProjectRoot(); + // eslint-disable-next-line depend/ban-dependencies + const globby = (await import('globby')).globby; + + const packageJsonFiles = await globby(['**/package.json'], { + ...commonGlobOptions(''), + ignore: ['**/node_modules/**'], + cwd: projectRoot, + gitignore: true, + }); + + // check if any of the package.json files have consolidated packages + const hasConsolidatedDependencies = await Promise.all( + packageJsonFiles.map(async (file) => { + const contents = await readFile(file, 'utf-8'); + const packageJson = JSON.parse(contents); + return ( + Object.keys(packageJson.dependencies || {}).some((dep) => dep in consolidatedPackages) || + Object.keys(packageJson.devDependencies || {}).some((dep) => dep in consolidatedPackages) + ); + }) + ).then((results) => results.some(Boolean)); + + if (!hasConsolidatedDependencies) { + return null; + } + return { + packageJsonFiles, + }; + }, + prompt: (result: ConsolidatedOptions) => { + return dedent` + Found package.json files that contain consolidated Storybook packages that need to be updated: + ${result.packageJsonFiles.map((file) => `- ${file}`).join('\n')} + + These packages have been consolidated into the main storybook package and should be removed. + The main storybook package will be added to devDependencies if not already present. + + Would you like to: + 1. Update these package.json files + 2. Scan your codebase and update any imports from these consolidated packages + + This will ensure your project is properly updated to use the new consolidated package structure. + `; + }, + run: async (options: RunOptions) => { + const { result, dryRun = false } = options; + const { packageJsonFiles } = result; + + const errors: Array<{ file: string; error: Error }> = []; + + const packageJsonErrors = await transformPackageJsonFiles(packageJsonFiles, dryRun); + errors.push(...packageJsonErrors); + + const projectRoot = getProjectRoot(); + + const defaultGlob = '**/*.{mjs,cjs,js,jsx,ts,tsx}'; + // Find all files matching the glob pattern + const { glob } = await prompts({ + type: 'text', + name: 'glob', + message: 'Enter a custom glob pattern to scan (or press enter to use default):', + initial: defaultGlob, + }); + + // eslint-disable-next-line depend/ban-dependencies + const globby = (await import('globby')).globby; + + const sourceFiles = await globby([glob], { + ...commonGlobOptions(''), + ignore: ['**/node_modules/**'], + dot: true, + cwd: projectRoot, + }); + + const importErrors = await transformImportFiles(sourceFiles, dryRun); + errors.push(...importErrors); + + if (errors.length > 0) { + // eslint-disable-next-line local-rules/no-uncategorized-errors + throw new Error( + `Failed to process ${errors.length} files:\n${errors + .map(({ file, error }) => `- ${file}: ${error.message}`) + .join('\n')}` + ); + } + + if (!dryRun && result.packageJsonFiles.length > 0) { + await options.packageManager.installDependencies(); + } + }, +}; diff --git a/code/lib/cli-storybook/src/automigrate/fixes/index.ts b/code/lib/cli-storybook/src/automigrate/fixes/index.ts index 60f009ee14b4..87f11b336902 100644 --- a/code/lib/cli-storybook/src/automigrate/fixes/index.ts +++ b/code/lib/cli-storybook/src/automigrate/fixes/index.ts @@ -9,19 +9,18 @@ import { angularBuildersMultiproject } from './angular-builders-multiproject'; import { autodocsTags } from './autodocs-tags'; import { autodocsTrue } from './autodocs-true'; import { builderVite } from './builder-vite'; +import { consolidatedImports } from './consolidated-imports'; import { cra5 } from './cra5'; import { eslintPlugin } from './eslint-plugin'; import { initialGlobals } from './initial-globals'; import { mdx1to3 } from './mdx-1-to-3'; import { mdxgfm } from './mdx-gfm'; import { mdxToCSF } from './mdx-to-csf'; -import { missingStorybookDependencies } from './missing-storybook-dependencies'; import { newFrameworks } from './new-frameworks'; import { removeReactDependency } from './prompt-remove-react'; import { reactDocgen } from './react-docgen'; import { removeArgtypesRegex } from './remove-argtypes-regex'; import { removedGlobalClientAPIs } from './remove-global-client-apis'; -import { removeJestTestingLibrary } from './remove-jest-testing-library'; import { removeLegacyMDX1 } from './remove-legacymdx1'; import { sbBinary } from './sb-binary'; import { sbScripts } from './sb-scripts'; @@ -37,7 +36,6 @@ import { wrapRequire } from './wrap-require'; export * from '../types'; export const allFixes: Fix[] = [ - missingStorybookDependencies, addonsAPI, newFrameworks, cra5, @@ -49,7 +47,6 @@ export const allFixes: Fix[] = [ builderVite, sbBinary, sbScripts, - removeJestTestingLibrary, removeArgtypesRegex, removedGlobalClientAPIs, mdxgfm, @@ -69,6 +66,7 @@ export const allFixes: Fix[] = [ autodocsTags, initialGlobals, addonA11yAddonTest, + consolidatedImports, addonExperimentalTest, ]; diff --git a/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.test.ts deleted file mode 100644 index 3663cf3f0bdc..000000000000 --- a/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; - -import type { JsPackageManager } from 'storybook/internal/common'; - -import stripAnsi from 'strip-ansi'; - -import { missingStorybookDependencies } from './missing-storybook-dependencies'; - -vi.mock('globby', () => ({ - __esModule: true, - globby: vi.fn().mockResolvedValue(['.storybook/manager.ts', 'path/to/file.stories.tsx']), -})); - -vi.mock('node:fs/promises', async (importOriginal) => { - const original = (await importOriginal()) as typeof import('node:fs/promises'); - return { - ...original, - readFile: vi.fn().mockResolvedValue(` - // these are NOT installed, will be reported - import { someFunction } from '@storybook/preview-api'; - import { anotherFunction } from '@storybook/manager-api'; - import { SomeError } from '@storybook/core-events/server-errors'; - // this IS installed, will not be reported - import { yetAnotherFunction } from '@storybook/theming'; - `), - }; -}); - -vi.mock('../../helpers', () => ({ - getStorybookVersionSpecifier: vi.fn().mockReturnValue('^8.1.10'), -})); - -const check = async ({ - packageManager, - storybookVersion = '8.1.10', -}: { - packageManager: JsPackageManager; - storybookVersion?: string; -}) => { - return missingStorybookDependencies.check({ - packageManager, - mainConfig: {} as any, - storybookVersion, - }); -}; - -describe('missingStorybookDependencies', () => { - const mockPackageManager = { - findInstallations: vi.fn().mockResolvedValue({ - dependencies: { - '@storybook/react': '8.1.0', - '@storybook/theming': '8.1.0', - }, - }), - retrievePackageJson: vi.fn().mockResolvedValue({ - dependencies: { - storybook: '8.1.0', - }, - }), - addDependencies: vi.fn().mockResolvedValue(undefined), - } as Partial; - - describe('check function', () => { - it('should identify missing dependencies', async () => { - const result = await check({ - packageManager: mockPackageManager as JsPackageManager, - }); - - expect(Object.keys(result!.packageUsage)).not.includes('@storybook/theming'); - expect(result).toEqual({ - packageUsage: { - '@storybook/preview-api': ['.storybook/manager.ts', 'path/to/file.stories.tsx'], - '@storybook/manager-api': ['.storybook/manager.ts', 'path/to/file.stories.tsx'], - '@storybook/core-events': ['.storybook/manager.ts', 'path/to/file.stories.tsx'], - }, - }); - }); - }); - - describe('prompt function', () => { - it('should provide a proper message with the missing dependencies', () => { - const packageUsage = { - '@storybook/preview-api': ['.storybook/manager.ts'], - '@storybook/manager-api': ['path/to/file.stories.tsx'], - }; - - const message = missingStorybookDependencies.prompt({ packageUsage }); - - expect(stripAnsi(message)).toMatchInlineSnapshot(` - "Found the following Storybook packages used in your project, but they are missing from your project dependencies: - - @storybook/manager-api: (1 file) - - @storybook/preview-api: (1 file) - - Referencing missing packages can cause your project to crash. We can automatically add them to your dependencies. - - More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#failed-to-resolve-import-storybookx-error" - `); - }); - }); - - describe('run function', () => { - it('should add missing dependencies', async () => { - const dryRun = false; - const packageUsage = { - '@storybook/preview-api': ['.storybook/manager.ts'], - '@storybook/manager-api': ['path/to/file.stories.tsx'], - }; - - await missingStorybookDependencies.run!({ - result: { packageUsage }, - dryRun, - packageJson: {}, - mainConfig: { stories: [] }, - packageManager: mockPackageManager as JsPackageManager, - mainConfigPath: 'path/to/main-config.js', - }); - - expect(mockPackageManager.addDependencies).toHaveBeenNthCalledWith( - 1, - { installAsDevDependencies: true }, - ['@storybook/preview-api@8.1.0', '@storybook/manager-api@8.1.0'] - ); - expect(mockPackageManager.addDependencies).toHaveBeenNthCalledWith( - 2, - { installAsDevDependencies: true, skipInstall: true, packageJson: expect.anything() }, - ['@storybook/preview-api@8.1.0', '@storybook/manager-api@8.1.0'] - ); - }); - }); -}); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.ts b/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.ts deleted file mode 100644 index 7e36f4750284..000000000000 --- a/code/lib/cli-storybook/src/automigrate/fixes/missing-storybook-dependencies.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { readFile } from 'node:fs/promises'; - -import { getStorybookVersionSpecifier } from 'storybook/internal/cli'; -import type { InstallationMetadata, JsPackageManager } from 'storybook/internal/common'; - -import picocolors from 'picocolors'; -import { dedent } from 'ts-dedent'; - -import type { Fix } from '../types'; - -const logger = console; - -type PackageUsage = Record; - -interface MissingStorybookDependenciesOptions { - packageUsage: PackageUsage; -} - -const consolidatedPackages = [ - '@storybook/channels', - '@storybook/client-logger', - '@storybook/core-common', - '@storybook/core-events', - '@storybook/csf-tools', - '@storybook/docs-tools', - '@storybook/node-logger', - '@storybook/preview-api', - '@storybook/router', - '@storybook/telemetry', - '@storybook/theming', - '@storybook/types', - '@storybook/manager-api', - '@storybook/manager', - '@storybook/preview', - '@storybook/core-server', - '@storybook/builder-manager', - '@storybook/components', -]; - -async function checkInstallations( - packageManager: JsPackageManager, - packages: string[] -): Promise { - let result: Record = {}; - - // go through each package and get installation info at depth 0 to make sure - // the dependency is directly installed, else they could come from other dependencies - const promises = packages.map((pkg) => packageManager.findInstallations([pkg], { depth: 0 })); - - const analyses = await Promise.all(promises); - - analyses.forEach((analysis) => { - if (analysis?.dependencies) { - result = { - ...result, - ...analysis.dependencies, - }; - } - }); - - return result; -} - -/** Find usage of Storybook packages in the project files which are not present in the dependencies. */ -export const missingStorybookDependencies: Fix = { - id: 'missingStorybookDependencies', - promptType: 'auto', - versionRange: ['<8.2', '>=8.2'], - - async check({ packageManager }) { - // Dynamically import globby because it is a pure ESM module - // eslint-disable-next-line depend/ban-dependencies - const { globby } = await import('globby'); - - const result = await checkInstallations(packageManager, consolidatedPackages); - if (!result) { - return null; - } - - const installedDependencies = Object.keys(result).sort(); - const dependenciesToCheck = consolidatedPackages.filter( - (pkg) => !installedDependencies.includes(pkg) - ); - - const patterns = ['**/.storybook/*', '**/*.stories.*', '**/*.story.*']; - - const files = await globby(patterns, { - ignore: ['**/node_modules/**'], - }); - const packageUsage: PackageUsage = {}; - - for (const file of files) { - const content = await readFile(file, 'utf-8'); - dependenciesToCheck.forEach((pkg) => { - // match imports like @storybook/theming or @storybook/theming/create - const regex = new RegExp(`['"]${pkg}(/[^'"]*)?['"]`); - if (regex.test(content)) { - if (!packageUsage[pkg]) { - packageUsage[pkg] = []; - } - packageUsage[pkg].push(file); - } - }); - } - - return Object.keys(packageUsage).length > 0 ? { packageUsage } : null; - }, - - prompt({ packageUsage }) { - return dedent` - Found the following Storybook packages used in your project, but they are missing from your project dependencies: - ${Object.entries(packageUsage) - .map( - ([pkg, files]) => - `- ${picocolors.cyan(pkg)}: (${files.length} ${files.length === 1 ? 'file' : 'files'})` - ) - .sort() - .join('\n')} - - Referencing missing packages can cause your project to crash. We can automatically add them to your dependencies. - - More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#failed-to-resolve-import-storybookx-error - `; - }, - - async run({ result: { packageUsage }, dryRun, packageManager }) { - logger.info( - `✅ Installing the following packages as devDependencies: ${Object.keys(packageUsage)}` - ); - if (!dryRun) { - console.log(packageManager.retrievePackageJson()); - const dependenciesToInstall = Object.keys(packageUsage); - const versionToInstall = getStorybookVersionSpecifier( - await packageManager.retrievePackageJson() - ); - - const versionToInstallWithoutModifiers = versionToInstall?.replace(/[\^~]/, ''); - - /** - * WORKAROUND: necessary for the following scenario: Storybook latest is currently at 8.2.2 - * User has all Storybook deps at ^8.2.1 We run e.g. npm install with the dependency@^8.2.1 - * The package.json will have ^8.2.1 but install 8.2.2 So we first install the exact version, - * then run code again to write to package.json to add the caret back, but without running - * install - */ - await packageManager.addDependencies( - { installAsDevDependencies: true }, - dependenciesToInstall.map((pkg) => `${pkg}@${versionToInstallWithoutModifiers}`) - ); - const packageJson = await packageManager.retrievePackageJson(); - await packageManager.addDependencies( - { installAsDevDependencies: true, skipInstall: true, packageJson }, - dependenciesToInstall.map((pkg) => `${pkg}@${versionToInstall}`) - ); - } - }, -}; diff --git a/code/lib/cli-storybook/src/automigrate/fixes/remove-jest-testing-library.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/remove-jest-testing-library.test.ts deleted file mode 100644 index 80e5e4989bad..000000000000 --- a/code/lib/cli-storybook/src/automigrate/fixes/remove-jest-testing-library.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { expect, it } from 'vitest'; - -import type { JsPackageManager } from 'storybook/internal/common'; -import type { StorybookConfig } from 'storybook/internal/types'; - -import ansiRegex from 'ansi-regex'; - -import { removeJestTestingLibrary } from './remove-jest-testing-library'; - -const check = async ({ - packageManager, - main: mainConfig = {}, - storybookVersion = '8.0.0', -}: { - packageManager: Partial; - main?: Partial & Record; - storybookVersion?: string; -}) => { - return removeJestTestingLibrary.check({ - packageManager: packageManager as any, - configDir: '', - mainConfig: mainConfig as any, - storybookVersion, - }); -}; - -it('should prompt to install the test package and run the codemod', async () => { - const options = await check({ - packageManager: { - getAllDependencies: async () => ({ - '@storybook/jest': '1.0.0', - '@storybook/testing-library': '1.0.0', - }), - }, - main: { addons: ['@storybook/essentials', '@storybook/addon-info'] }, - }); - - expect(options).toMatchInlineSnapshot(` - { - "incompatiblePackages": [ - "@storybook/jest", - "@storybook/testing-library", - ], - } - `); - - expect.addSnapshotSerializer({ - serialize: (value) => { - const stringVal = typeof value === 'string' ? value : value.toString(); - return stringVal.replace(ansiRegex(), ''); - }, - test: () => true, - }); - - expect(await removeJestTestingLibrary.prompt(options!)).toMatchInlineSnapshot(` - Attention: We've detected that you're using the following packages which are known to be incompatible since Storybook 8: - - - @storybook/jest - - @storybook/testing-library - - We will uninstall them for you and install @storybook/test instead. - - Also, we can help you migrate your stories to use the new package. - `); -}); diff --git a/code/lib/cli-storybook/src/automigrate/fixes/remove-jest-testing-library.ts b/code/lib/cli-storybook/src/automigrate/fixes/remove-jest-testing-library.ts deleted file mode 100644 index b7de9df0afc6..000000000000 --- a/code/lib/cli-storybook/src/automigrate/fixes/remove-jest-testing-library.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { getStorybookVersionSpecifier } from 'storybook/internal/cli'; - -import { runCodemod } from '@storybook/codemod'; - -import picocolors from 'picocolors'; -import prompts from 'prompts'; -import { dedent } from 'ts-dedent'; - -import type { Fix } from '../types'; - -const logger = console; - -export const removeJestTestingLibrary: Fix<{ incompatiblePackages: string[] }> = { - id: 'remove-jest-testing-library', - versionRange: ['<8.0.0-alpha.0', '>=8.0.0-alpha.0'], - promptType: 'auto', - async check({ packageManager }) { - const deps = await packageManager.getAllDependencies(); - - const incompatiblePackages = Object.keys(deps).filter( - (it) => it === '@storybook/jest' || it === '@storybook/testing-library' - ); - return incompatiblePackages.length ? { incompatiblePackages } : null; - }, - prompt({ incompatiblePackages }) { - return dedent` - ${picocolors.bold( - 'Attention' - )}: We've detected that you're using the following packages which are known to be incompatible since Storybook 8: - - ${incompatiblePackages.map((name) => `- ${picocolors.cyan(`${name}`)}`).join('\n')} - - We will uninstall them for you and install ${picocolors.cyan('@storybook/test')} instead. - - Also, we can help you migrate your stories to use the new package. - `; - }, - async run({ packageManager, dryRun }) { - if (!dryRun) { - const packageJson = await packageManager.retrievePackageJson(); - - await packageManager.removeDependencies({ skipInstall: true, packageJson }, [ - '@storybook/jest', - '@storybook/testing-library', - ]); - - const versionToInstall = getStorybookVersionSpecifier(packageJson); - - await packageManager.addDependencies({ installAsDevDependencies: true, packageJson }, [ - `@storybook/test@${versionToInstall}`, - ]); - - const { glob: globString } = await prompts({ - type: 'text', - name: 'glob', - message: 'Please enter the glob for your stories to migrate to @storybook/test', - initial: './src/**/*.stories.*', - }); - - if (globString) { - await runCodemod('migrate-to-test-package', { glob: globString, dryRun, logger }); - } - } - }, -}; diff --git a/code/lib/cli-storybook/src/automigrate/helpers/consolidated-packages.ts b/code/lib/cli-storybook/src/automigrate/helpers/consolidated-packages.ts new file mode 100644 index 000000000000..4880dad9498d --- /dev/null +++ b/code/lib/cli-storybook/src/automigrate/helpers/consolidated-packages.ts @@ -0,0 +1,27 @@ +/** + * Consolidated packages are packages that have been merged into the main storybook package. This + * object maps the old package name to the new package name. + */ +export const consolidatedPackages = { + '@storybook/channels': 'storybook/internal/channels', + '@storybook/client-logger': 'storybook/internal/client-logger', + '@storybook/core-common': 'storybook/internal/common', + '@storybook/core-events': 'storybook/internal/core-events', + '@storybook/csf-tools': 'storybook/internal/csf-tools', + '@storybook/docs-tools': 'storybook/internal/docs-tools', + '@storybook/node-logger': 'storybook/internal/node-logger', + '@storybook/preview-api': 'storybook/internal/preview-api', + '@storybook/router': 'storybook/internal/router', + '@storybook/telemetry': 'storybook/internal/telemetry', + '@storybook/theming': 'storybook/internal/theming', + '@storybook/types': 'storybook/internal/types', + '@storybook/manager-api': 'storybook/internal/manager-api', + '@storybook/manager': 'storybook/internal/manager', + '@storybook/preview': 'storybook/internal/preview', + '@storybook/core-server': 'storybook/internal/core-server', + '@storybook/builder-manager': 'storybook/internal/builder-manager', + '@storybook/components': 'storybook/internal/components', + '@storybook/test': 'storybook/test', +} as const; + +export type ConsolidatedPackage = keyof typeof consolidatedPackages; diff --git a/code/lib/cli-storybook/src/sandbox-templates.ts b/code/lib/cli-storybook/src/sandbox-templates.ts index d6000075ca04..3177a9820821 100644 --- a/code/lib/cli-storybook/src/sandbox-templates.ts +++ b/code/lib/cli-storybook/src/sandbox-templates.ts @@ -499,6 +499,9 @@ export const baseTemplates = { renderer: '@storybook/angular', builder: '@storybook/builder-webpack5', }, + modifications: { + extraDependencies: ['@angular-devkit/build-angular@next'], + }, skipTasks: ['e2e-tests-dev', 'bench', 'vitest-integration'], }, 'angular-cli/default-ts': { diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index fe3b1f62ef45..917b3738f2cf 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -32,7 +32,6 @@ "./dist/transforms/find-implicit-spies.js": "./dist/transforms/find-implicit-spies.js", "./dist/transforms/move-builtin-addons.js": "./dist/transforms/move-builtin-addons.js", "./dist/transforms/mdx-to-csf.js": "./dist/transforms/mdx-to-csf.js", - "./dist/transforms/migrate-to-test-package.js": "./dist/transforms/migrate-to-test-package.js", "./dist/transforms/storiesof-to-csf.js": "./dist/transforms/storiesof-to-csf.js", "./dist/transforms/update-addon-info.js": "./dist/transforms/update-addon-info.js", "./dist/transforms/update-organisation-name.js": "./dist/transforms/update-organisation-name.js", @@ -95,7 +94,6 @@ "./src/transforms/csf-hoist-story-annotations.js", "./src/transforms/find-implicit-spies.ts", "./src/transforms/add-component-parameters.js", - "./src/transforms/migrate-to-test-package.ts", "./src/transforms/move-builtin-addons.js", "./src/transforms/update-addon-info.js", "./src/transforms/update-organisation-name.js", diff --git a/code/lib/codemod/src/transforms/__tests__/migrate-to-test-package.test.ts b/code/lib/codemod/src/transforms/__tests__/migrate-to-test-package.test.ts deleted file mode 100644 index e3c2b2e517fa..000000000000 --- a/code/lib/codemod/src/transforms/__tests__/migrate-to-test-package.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { expect, test } from 'vitest'; - -import { dedent } from 'ts-dedent'; - -import transform from '../migrate-to-test-package'; - -expect.addSnapshotSerializer({ - serialize: (val: any) => (typeof val === 'string' ? val : val.toString()), - test: () => true, -}); - -const tsTransform = async (source: string) => - (await transform({ source, path: 'Component.stories.tsx' })).trim(); - -test('replace jest and testing-library with the test package', async () => { - const input = dedent` - import { expect } from '@storybook/jest'; - import { within, userEvent } from '@storybook/testing-library'; - `; - - expect(await tsTransform(input)).toMatchInlineSnapshot(` - import { expect } from '@storybook/test'; - import { userEvent, within } from '@storybook/test'; - `); -}); - -test('Make jest imports namespace imports', async () => { - const input = dedent` - import { expect, jest } from '@storybook/jest'; - import { within, userEvent } from '@storybook/testing-library'; - - const onFocusMock = jest.fn(); - const onSearchMock = jest.fn(); - - jest.spyOn(window, 'Something'); - `; - - expect(await tsTransform(input)).toMatchInlineSnapshot(` - import { expect } from '@storybook/test'; - import * as test from '@storybook/test'; - import { userEvent, within } from '@storybook/test'; - - const onFocusMock = test.fn(); - const onSearchMock = test.fn(); - - test.spyOn(window, 'Something'); - `); -}); diff --git a/code/lib/codemod/src/transforms/migrate-to-test-package.ts b/code/lib/codemod/src/transforms/migrate-to-test-package.ts deleted file mode 100644 index 9fffa57f7ad6..000000000000 --- a/code/lib/codemod/src/transforms/migrate-to-test-package.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable no-underscore-dangle */ -import { type BabelFile, core as babel, types as t } from 'storybook/internal/babel'; -import { loadCsf, printCsf } from 'storybook/internal/csf-tools'; - -import type { FileInfo } from 'jscodeshift'; -import prettier from 'prettier'; - -export default async function transform(info: FileInfo) { - const csf = loadCsf(info.source, { makeTitle: (title) => title }); - const fileNode = csf._ast; - // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606 - const file: BabelFile = new babel.File( - { filename: info.path }, - { code: info.source, ast: fileNode } - ); - - file.path.traverse({ - ImportDeclaration: (path) => { - if ( - path.node.source.value === '@storybook/jest' || - path.node.source.value === '@storybook/testing-library' - ) { - if (path.node.source.value === '@storybook/jest') { - path.get('specifiers').forEach((specifier) => { - if (specifier.isImportSpecifier()) { - const imported = specifier.get('imported'); - - if (!imported.isIdentifier()) { - return; - } - if (imported.node.name === 'jest') { - specifier.remove(); - path.insertAfter( - t.importDeclaration( - [t.importNamespaceSpecifier(t.identifier('test'))], - t.stringLiteral('@storybook/test') - ) - ); - } - } - }); - } - path.get('source').replaceWith(t.stringLiteral('@storybook/test')); - } - }, - Identifier: (path) => { - if (path.node.name === 'jest') { - path.replaceWith(t.identifier('test')); - } - }, - }); - - let output = printCsf(csf).code; - try { - output = await prettier.format(output, { - ...(await prettier.resolveConfig(info.path)), - filepath: info.path, - }); - } catch (e) { - console.warn(`Failed applying prettier to ${info.path}.`); - } - return output; -} - -export const parser = 'tsx'; diff --git a/code/lib/create-storybook/src/generators/ANGULAR/index.ts b/code/lib/create-storybook/src/generators/ANGULAR/index.ts index dfea1b03b318..1fa1bc2c53a1 100644 --- a/code/lib/create-storybook/src/generators/ANGULAR/index.ts +++ b/code/lib/create-storybook/src/generators/ANGULAR/index.ts @@ -73,7 +73,10 @@ const generator: Generator<{ projectName: string }> = async ( 'angular', { extraAddons: [`@storybook/addon-onboarding`], - ...(useCompodoc && { extraPackages: ['@compodoc/compodoc', '@storybook/addon-docs'] }), + extraPackages: [ + '@angular-devkit/build-angular', + ...(useCompodoc ? ['@compodoc/compodoc', '@storybook/addon-docs'] : []), + ], addScripts: false, componentsDestinationPath: root ? `${root}/src/stories` : undefined, storybookConfigFolder: storybookFolder, diff --git a/code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts b/code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts index 13d50bfb347e..bfe983ab5515 100644 --- a/code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts +++ b/code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts @@ -56,7 +56,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => { await copyTemplateFiles({ packageManager: packageManager as any, - renderer: 'react-native', + templateLocation: 'react-native', // this value for language is not used since we only ship the ts template. This means we just fallback to @storybook/react-native/template/cli. language: SupportedLanguage.TYPESCRIPT_4_9, destination: storybookConfigFolder, diff --git a/code/lib/create-storybook/src/generators/baseGenerator.ts b/code/lib/create-storybook/src/generators/baseGenerator.ts index 6f842d59e253..9d332674c68a 100644 --- a/code/lib/create-storybook/src/generators/baseGenerator.ts +++ b/code/lib/create-storybook/src/generators/baseGenerator.ts @@ -224,6 +224,7 @@ export async function baseGenerator( ProjectType.SVELTE, ProjectType.SVELTEKIT, ProjectType.WEB_COMPONENTS, + ProjectType.REACT_NATIVE_WEB, ]; const supportsTestAddon = projectType === ProjectType.NEXTJS || @@ -296,7 +297,6 @@ export async function baseGenerator( const addonPackages = [ '@storybook/addon-essentials', '@storybook/blocks', - '@storybook/test', ...(compiler ? [`@storybook/addon-webpack5-compiler-${compiler}`] : []), ...extraAddonsToInstall, ].filter(Boolean); @@ -448,7 +448,7 @@ export async function baseGenerator( throw new Error(`Could not find template location for ${framework} or ${rendererId}`); } await copyTemplateFiles({ - renderer: templateLocation, + templateLocation, packageManager: packageManager as any, language, destination: componentsDestinationPath, diff --git a/code/lib/create-storybook/src/scaffold-new-project.ts b/code/lib/create-storybook/src/scaffold-new-project.ts index cfbf63c41fe9..d86414b23aae 100644 --- a/code/lib/create-storybook/src/scaffold-new-project.ts +++ b/code/lib/create-storybook/src/scaffold-new-project.ts @@ -45,10 +45,10 @@ const SUPPORTED_PROJECTS: Record = { language: 'TS', }, createScript: { - npm: 'npm create next-app@^14 . -- --typescript --use-npm --eslint --tailwind --no-app --import-alias="@/*" --src-dir', + npm: 'npm create next-app . -- --turbopack --typescript --use-npm --eslint --tailwind --no-app --import-alias="@/*" --src-dir', // yarn doesn't support version ranges, so we have to use npx - yarn: 'npx create-next-app@^14 . --typescript --use-yarn --eslint --tailwind --no-app --import-alias="@/*" --src-dir', - pnpm: 'pnpm create next-app@^14 . --typescript --use-pnpm --eslint --tailwind --no-app --import-alias="@/*" --src-dir', + yarn: 'npx create-next-app . --turbopack --typescript --use-yarn --eslint --tailwind --no-app --import-alias="@/*" --src-dir', + pnpm: 'pnpm create next-app . --turbopack --typescript --use-pnpm --eslint --tailwind --no-app --import-alias="@/*" --src-dir', }, }, 'vue-vite-ts': { diff --git a/code/lib/test/package.json b/code/lib/test/package.json deleted file mode 100644 index 5082b1881b26..000000000000 --- a/code/lib/test/package.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "name": "@storybook/test", - "version": "9.0.0-alpha.2", - "description": "", - "keywords": [ - "storybook" - ], - "homepage": "https://github.com/storybookjs/storybook/tree/next/code/lib/test", - "bugs": { - "url": "https://github.com/storybookjs/storybook/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/storybookjs/storybook.git", - "directory": "code/lib/test" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "license": "MIT", - "sideEffects": true, - "exports": { - ".": { - "types": "./dist/index.d.ts", - "node": "./dist/index.js", - "import": "./dist/index.mjs", - "require": "./dist/index.js" - }, - "./package.json": "./package.json" - }, - "main": "dist/index.js", - "module": "dist/index.mjs", - "types": "dist/index.d.ts", - "files": [ - "dist/**/*", - "README.md", - "*.js", - "*.d.ts" - ], - "scripts": { - "check": "jiti ../../../scripts/prepare/check.ts", - "prep": "jiti ../../../scripts/prepare/bundle.ts" - }, - "dependencies": { - "@storybook/global": "^5.0.0", - "@testing-library/dom": "10.4.0", - "@testing-library/jest-dom": "6.5.0", - "@testing-library/user-event": "14.5.2", - "@vitest/expect": "2.0.5", - "@vitest/spy": "2.0.5" - }, - "devDependencies": { - "chai": "^5.1.1", - "tinyspy": "^3.0.0", - "ts-dedent": "^2.2.0", - "type-fest": "~2.19", - "typescript": "^5.7.3" - }, - "peerDependencies": { - "storybook": "workspace:^" - }, - "publishConfig": { - "access": "public" - }, - "bundler": { - "entries": [ - "./src/index.ts" - ], - "noExternal": [ - "@testing-library/dom", - "@testing-library/jest-dom", - "@testing-library/user-event", - "chai", - "@vitest/expect", - "@vitest/spy", - "@vitest/utils" - ], - "externals": [ - "util" - ] - }, - "gitHead": "e6a7fd8a655c69780bc20b9749c2699e44beae16" -} diff --git a/code/lib/test/project.json b/code/lib/test/project.json deleted file mode 100644 index 1302a230f1e1..000000000000 --- a/code/lib/test/project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "test", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "projectType": "library", - "targets": { - "build": {} - } -} diff --git a/code/lib/test/template/stories/utils.mock.ts b/code/lib/test/template/stories/utils.mock.ts deleted file mode 100644 index 93a72d03a0e2..000000000000 --- a/code/lib/test/template/stories/utils.mock.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { fn } from '@storybook/test'; - -import * as utils from './utils.ts'; - -export const foo = fn(utils.foo).mockName('foo'); diff --git a/code/lib/test/template/stories/utils.ts b/code/lib/test/template/stories/utils.ts deleted file mode 100644 index 5a80b1903c1f..000000000000 --- a/code/lib/test/template/stories/utils.ts +++ /dev/null @@ -1 +0,0 @@ -export const foo = () => 'not mocked'; diff --git a/code/lib/test/tsconfig.json b/code/lib/test/tsconfig.json deleted file mode 100644 index 73a65ef2ef6e..000000000000 --- a/code/lib/test/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": {}, - "include": ["src/**/*"] -} diff --git a/code/lib/test/vitest.config.ts b/code/lib/test/vitest.config.ts deleted file mode 100644 index 7420176b2e46..000000000000 --- a/code/lib/test/vitest.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig, mergeConfig } from 'vitest/config'; - -import { vitestCommonConfig } from '../../vitest.workspace'; - -export default mergeConfig( - vitestCommonConfig, - defineConfig({ - // Add custom config here - }) -); diff --git a/code/package.json b/code/package.json index 993a1ab476a6..e47578db9048 100644 --- a/code/package.json +++ b/code/package.json @@ -153,7 +153,6 @@ "@storybook/source-loader": "workspace:*", "@storybook/svelte": "workspace:*", "@storybook/svelte-webpack5": "workspace:*", - "@storybook/test": "workspace:*", "@storybook/testing-library": "next", "@storybook/vue3": "workspace:*", "@storybook/vue3-vite": "workspace:*", @@ -162,8 +161,8 @@ "@storybook/web-components-vite": "workspace:*", "@storybook/web-components-webpack5": "workspace:*", "@testing-library/dom": "^10.4.0", - "@testing-library/jest-dom": "^6.5.0", - "@testing-library/react": "^16.0.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.2.0", "@testing-library/user-event": "^14.5.2", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/mock-require": "^2.0.3", @@ -176,9 +175,9 @@ "@typescript-eslint/parser": "7.18.0", "@vitejs/plugin-react": "^4.3.2", "@vitejs/plugin-vue": "^4.4.0", - "@vitest/browser": "^3.0.2", - "@vitest/coverage-istanbul": "^3.0.2", - "@vitest/coverage-v8": "^3.0.2", + "@vitest/browser": "^3.0.8", + "@vitest/coverage-istanbul": "^3.0.8", + "@vitest/coverage-v8": "^3.0.8", "create-storybook": "workspace:*", "cross-env": "^7.0.3", "danger": "^12.3.3", @@ -192,7 +191,7 @@ "eslint-plugin-import": "^2.29.1", "eslint-plugin-local-rules": "portal:../scripts/eslint-plugin-local-rules", "eslint-plugin-playwright": "^1.6.2", - "eslint-plugin-storybook": "0.11.3--canary.187.1af857a.0", + "eslint-plugin-storybook": "0.11.4", "github-release-from-changelog": "^2.1.1", "glob": "^10.0.0", "happy-dom": "^14.12.0", @@ -225,7 +224,7 @@ "util": "^0.12.4", "vite": "^4.0.0", "vite-plugin-inspect": "^0.8.5", - "vitest": "^3.0.2", + "vitest": "^3.0.8", "wait-on": "^7.0.1" }, "dependenciesMeta": { @@ -298,5 +297,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "9.0.0-alpha.3" } diff --git a/code/renderers/html/template/cli/js/Button.stories.js b/code/renderers/html/template/cli/js/Button.stories.js index 985eb1f26e1e..36ffffe5f270 100644 --- a/code/renderers/html/template/cli/js/Button.stories.js +++ b/code/renderers/html/template/cli/js/Button.stories.js @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { createButton } from './Button'; diff --git a/code/renderers/html/template/cli/js/Header.stories.js b/code/renderers/html/template/cli/js/Header.stories.js index 1168c39159ce..5c9949fe83f5 100644 --- a/code/renderers/html/template/cli/js/Header.stories.js +++ b/code/renderers/html/template/cli/js/Header.stories.js @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { createHeader } from './Header'; diff --git a/code/renderers/html/template/cli/js/Page.stories.js b/code/renderers/html/template/cli/js/Page.stories.js index 4e98ad615cd7..17002143e81f 100644 --- a/code/renderers/html/template/cli/js/Page.stories.js +++ b/code/renderers/html/template/cli/js/Page.stories.js @@ -1,4 +1,4 @@ -import { expect, userEvent, within } from '@storybook/test'; +import { expect, userEvent, within } from 'storybook/test'; import { createPage } from './Page'; diff --git a/code/renderers/html/template/cli/ts-4-9/Button.stories.ts b/code/renderers/html/template/cli/ts-4-9/Button.stories.ts index e65f93d20f02..8e3e8fceb299 100644 --- a/code/renderers/html/template/cli/ts-4-9/Button.stories.ts +++ b/code/renderers/html/template/cli/ts-4-9/Button.stories.ts @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/html'; -import { fn } from '@storybook/test'; + +import { fn } from 'storybook/test'; import type { ButtonProps } from './Button'; import { createButton } from './Button'; diff --git a/code/renderers/html/template/cli/ts-4-9/Header.stories.ts b/code/renderers/html/template/cli/ts-4-9/Header.stories.ts index 93bc0f66b4a8..5a119106099b 100644 --- a/code/renderers/html/template/cli/ts-4-9/Header.stories.ts +++ b/code/renderers/html/template/cli/ts-4-9/Header.stories.ts @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/html'; -import { fn } from '@storybook/test'; + +import { fn } from 'storybook/test'; import type { HeaderProps } from './Header'; import { createHeader } from './Header'; diff --git a/code/renderers/html/template/cli/ts-4-9/Page.stories.ts b/code/renderers/html/template/cli/ts-4-9/Page.stories.ts index 5aa9e689913e..b5b06055caca 100644 --- a/code/renderers/html/template/cli/ts-4-9/Page.stories.ts +++ b/code/renderers/html/template/cli/ts-4-9/Page.stories.ts @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/html'; -import { expect, userEvent, within } from '@storybook/test'; + +import { expect, userEvent, within } from 'storybook/test'; import { createPage } from './Page'; diff --git a/code/renderers/preact/template/cli/Button.stories.jsx b/code/renderers/preact/template/cli/Button.stories.jsx index 94fd8d336e48..0cc0adf6def4 100644 --- a/code/renderers/preact/template/cli/Button.stories.jsx +++ b/code/renderers/preact/template/cli/Button.stories.jsx @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/renderers/preact/template/cli/Header.stories.jsx b/code/renderers/preact/template/cli/Header.stories.jsx index 7cb7da7cd8ca..6d88e1007498 100644 --- a/code/renderers/preact/template/cli/Header.stories.jsx +++ b/code/renderers/preact/template/cli/Header.stories.jsx @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { Header } from './Header'; diff --git a/code/renderers/preact/template/cli/Page.stories.jsx b/code/renderers/preact/template/cli/Page.stories.jsx index b7a417b634f0..478ae05a8705 100644 --- a/code/renderers/preact/template/cli/Page.stories.jsx +++ b/code/renderers/preact/template/cli/Page.stories.jsx @@ -1,4 +1,4 @@ -import { userEvent, within } from '@storybook/test'; +import { userEvent, within } from 'storybook/test'; import { Page } from './Page'; diff --git a/code/renderers/react/package.json b/code/renderers/react/package.json index 4ab865a78af3..9f4e0098a139 100644 --- a/code/renderers/react/package.json +++ b/code/renderers/react/package.json @@ -74,7 +74,6 @@ "@storybook/react-dom-shim": "workspace:*" }, "devDependencies": { - "@storybook/test": "workspace:*", "@types/babel-plugin-react-docgen": "^4.2.3", "@types/escodegen": "^0.0.6", "@types/estree": "^0.0.51", @@ -96,16 +95,12 @@ "type-fest": "~2.19" }, "peerDependencies": { - "@storybook/test": "workspace:*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "storybook": "workspace:^", "typescript": ">= 4.9.x" }, "peerDependenciesMeta": { - "@storybook/test": { - "optional": true - }, "typescript": { "optional": true } diff --git a/code/renderers/react/src/__test__/Button.csf4.stories.tsx b/code/renderers/react/src/__test__/Button.csf4.stories.tsx index 71e8eafa02a8..19b9c20460e6 100644 --- a/code/renderers/react/src/__test__/Button.csf4.stories.tsx +++ b/code/renderers/react/src/__test__/Button.csf4.stories.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; -import { expect, fn, mocked, userEvent, within } from '@storybook/test'; - import { action } from '@storybook/addon-actions'; +import { expect, fn, mocked, userEvent, within } from 'storybook/test'; + import { __definePreview } from '../preview'; import { Button } from './Button'; diff --git a/code/renderers/react/src/__test__/Button.stories.tsx b/code/renderers/react/src/__test__/Button.stories.tsx index 0e6e0d6e8c67..134748e8b347 100644 --- a/code/renderers/react/src/__test__/Button.stories.tsx +++ b/code/renderers/react/src/__test__/Button.stories.tsx @@ -1,11 +1,11 @@ import React, { useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; -import { expect, fn, mocked, userEvent, within } from '@storybook/test'; - import type { HandlerFunction } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions'; +import { expect, fn, mocked, userEvent, within } from 'storybook/test'; + import type { StoryFn as CSF2Story, StoryObj as CSF3Story, Meta } from '..'; import type { ButtonProps } from './Button'; import { Button } from './Button'; diff --git a/code/renderers/react/src/csf-factories.test.tsx b/code/renderers/react/src/csf-factories.test.tsx index 3289e3394ec0..7a9aa5093d7b 100644 --- a/code/renderers/react/src/csf-factories.test.tsx +++ b/code/renderers/react/src/csf-factories.test.tsx @@ -9,10 +9,9 @@ import React from 'react'; import type { Canvas } from 'storybook/internal/csf'; import type { Args, StrictArgs } from 'storybook/internal/types'; -import type { Mock } from '@storybook/test'; -import { fn } from '@storybook/test'; - import { expectTypeOf } from 'expect-type'; +import { fn } from 'storybook/test'; +import type { Mock } from 'storybook/test'; import { __definePreview } from './preview'; import type { Decorator } from './public-types'; diff --git a/code/renderers/react/src/entry-preview.tsx b/code/renderers/react/src/entry-preview.tsx index b2e6c1de5b18..7c83cd3f45bc 100644 --- a/code/renderers/react/src/entry-preview.tsx +++ b/code/renderers/react/src/entry-preview.tsx @@ -30,7 +30,7 @@ export const beforeAll = async () => { try { // copied from // https://github.com/testing-library/react-testing-library/blob/3dcd8a9649e25054c0e650d95fca2317b7008576/src/pure.js - const { configure } = await import('@storybook/test'); + const { configure } = await import('storybook/test'); configure({ unstable_advanceTimersWrapper: (cb) => { @@ -73,7 +73,7 @@ export const beforeAll = async () => { }); } catch (e) { // no-op - // @storybook/test might not be available + // storybook/test might not be available } }; diff --git a/code/renderers/react/src/public-types.test.tsx b/code/renderers/react/src/public-types.test.tsx index 42544c6bb150..45a36ab1d015 100644 --- a/code/renderers/react/src/public-types.test.tsx +++ b/code/renderers/react/src/public-types.test.tsx @@ -9,10 +9,9 @@ import { satisfies } from 'storybook/internal/common'; import type { Canvas } from 'storybook/internal/csf'; import type { Args, StoryAnnotations, StrictArgs } from 'storybook/internal/types'; -import type { Mock } from '@storybook/test'; -import { fn } from '@storybook/test'; - import { expectTypeOf } from 'expect-type'; +import { fn } from 'storybook/test'; +import type { Mock } from 'storybook/test'; import type { SetOptional } from 'type-fest'; import type { Decorator, Meta, StoryObj } from './public-types'; diff --git a/code/renderers/react/template/cli/js/Button.stories.js b/code/renderers/react/template/cli/js/Button.stories.js index 045d9c477ab1..1b56021e71d9 100644 --- a/code/renderers/react/template/cli/js/Button.stories.js +++ b/code/renderers/react/template/cli/js/Button.stories.js @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/renderers/react/template/cli/js/Header.stories.js b/code/renderers/react/template/cli/js/Header.stories.js index 7cb7da7cd8ca..6d88e1007498 100644 --- a/code/renderers/react/template/cli/js/Header.stories.js +++ b/code/renderers/react/template/cli/js/Header.stories.js @@ -1,4 +1,4 @@ -import { fn } from '@storybook/test'; +import { fn } from 'storybook/test'; import { Header } from './Header'; diff --git a/code/renderers/react/template/cli/js/Page.stories.js b/code/renderers/react/template/cli/js/Page.stories.js index 7b9906a73514..1ffea36cf374 100644 --- a/code/renderers/react/template/cli/js/Page.stories.js +++ b/code/renderers/react/template/cli/js/Page.stories.js @@ -1,4 +1,4 @@ -import { expect, userEvent, within } from '@storybook/test'; +import { expect, userEvent, within } from 'storybook/test'; import { Page } from './Page'; diff --git a/code/renderers/react/template/cli/ts-4-9/Button.stories.ts b/code/renderers/react/template/cli/ts-4-9/Button.stories.ts index 2a05e01b06fe..535e1b3fd965 100644 --- a/code/renderers/react/template/cli/ts-4-9/Button.stories.ts +++ b/code/renderers/react/template/cli/ts-4-9/Button.stories.ts @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; + +import { fn } from 'storybook/test'; import { Button } from './Button'; diff --git a/code/renderers/react/template/cli/ts-4-9/Header.stories.ts b/code/renderers/react/template/cli/ts-4-9/Header.stories.ts index 80c71d0f520e..b233bcb4f4d0 100644 --- a/code/renderers/react/template/cli/ts-4-9/Header.stories.ts +++ b/code/renderers/react/template/cli/ts-4-9/Header.stories.ts @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; + +import { fn } from 'storybook/test'; import { Header } from './Header'; diff --git a/code/renderers/react/template/cli/ts-4-9/Page.stories.ts b/code/renderers/react/template/cli/ts-4-9/Page.stories.ts index 5d2c688a978f..6c39800e3e5c 100644 --- a/code/renderers/react/template/cli/ts-4-9/Page.stories.ts +++ b/code/renderers/react/template/cli/ts-4-9/Page.stories.ts @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; + +import { expect, userEvent, within } from 'storybook/test'; import { Page } from './Page'; diff --git a/code/renderers/svelte/src/__test__/composeStories/Button.stories.ts b/code/renderers/svelte/src/__test__/composeStories/Button.stories.ts index 92ade46f29a8..9bc3ad429f8c 100644 --- a/code/renderers/svelte/src/__test__/composeStories/Button.stories.ts +++ b/code/renderers/svelte/src/__test__/composeStories/Button.stories.ts @@ -1,4 +1,4 @@ -import { expect, fn, userEvent, within } from '@storybook/test'; +import { expect, fn, userEvent, within } from 'storybook/test'; import type { StoryFn as CSF2Story, Meta, StoryObj } from '../..'; import AddWrapperDecorator from './AddWrapperDecorator.svelte'; diff --git a/code/renderers/svelte/template/cli/js/Page.stories.js b/code/renderers/svelte/template/cli/js/Page.stories.js index 5ce7b3dac56f..7355660af638 100644 --- a/code/renderers/svelte/template/cli/js/Page.stories.js +++ b/code/renderers/svelte/template/cli/js/Page.stories.js @@ -1,4 +1,4 @@ -import { expect, userEvent, waitFor, within } from '@storybook/test'; +import { expect, userEvent, waitFor, within } from 'storybook/test'; import Page from './Page.svelte'; diff --git a/code/renderers/svelte/template/cli/svelte-5-js/Button.stories.svelte b/code/renderers/svelte/template/cli/svelte-5-js/Button.stories.svelte index 4c8c7cce632a..e6fb72dac174 100644 --- a/code/renderers/svelte/template/cli/svelte-5-js/Button.stories.svelte +++ b/code/renderers/svelte/template/cli/svelte-5-js/Button.stories.svelte @@ -1,7 +1,7 @@