mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-07 07:21:17 +08:00
Merge branch 'next' of github.com:storybookjs/storybook into jeppe/support-svelte-csf-in-vitest
This commit is contained in:
commit
7c95fe08ef
@ -1,3 +1,24 @@
|
||||
## 8.5.0-beta.7
|
||||
|
||||
- Addon Test: Context menu updates - [#30107](https://github.com/storybookjs/storybook/pull/30107), thanks @ghengeveld!
|
||||
- Storysource Addon: Fix source-loader prettier imports - [#29669](https://github.com/storybookjs/storybook/pull/29669), thanks @slax57!
|
||||
- Vue: Extend sourceDecorator to support v-bind and nested keys in slots - [#28787](https://github.com/storybookjs/storybook/pull/28787), thanks @JoCa96!
|
||||
|
||||
## 8.5.0-beta.6
|
||||
|
||||
- Addon Test: Always use installed version of vitest - [#30134](https://github.com/storybookjs/storybook/pull/30134), thanks @kasperpeulen!
|
||||
- Addon Test: Fix documentation links - [#30128](https://github.com/storybookjs/storybook/pull/30128), thanks @yannbf!
|
||||
- Addon Test: Use correct vitest config file path - [#30135](https://github.com/storybookjs/storybook/pull/30135), thanks @kasperpeulen!
|
||||
- Automigration: Improve addon-a11y-addon-test - [#30127](https://github.com/storybookjs/storybook/pull/30127), thanks @valentinpalkovic!
|
||||
|
||||
## 8.5.0-beta.5
|
||||
|
||||
- Addon Test: Only reset story count on file change when watch mode is enabled - [#30121](https://github.com/storybookjs/storybook/pull/30121), thanks @ghengeveld!
|
||||
- Build: Revert Downgrade to esbuild 0.24.0 - [#30120](https://github.com/storybookjs/storybook/pull/30120), thanks @yannbf!
|
||||
- Core: Fix `ERR_PACKAGE_PATH_NOT_EXPORTED` in `@storybook/node-logger` - [#30093](https://github.com/storybookjs/storybook/pull/30093), thanks @JReinhold!
|
||||
- React: Use Act wrapper in Storybook for component rendering - [#30037](https://github.com/storybookjs/storybook/pull/30037), thanks @valentinpalkovic!
|
||||
- Vite: Add extra entries to `optimizeDeps` - [#30117](https://github.com/storybookjs/storybook/pull/30117), thanks @ndelangen!
|
||||
|
||||
## 8.5.0-beta.4
|
||||
|
||||
- Addon Themes: Deprecate useThemeParameters - [#30111](https://github.com/storybookjs/storybook/pull/30111), thanks @yannbf!
|
||||
|
@ -4,6 +4,7 @@ import type { StorybookConfig } from '../frameworks/react-vite';
|
||||
|
||||
const componentsPath = join(__dirname, '../core/src/components');
|
||||
const managerApiPath = join(__dirname, '../core/src/manager-api');
|
||||
const imageContextPath = join(__dirname, '..//frameworks/nextjs/src/image-context.ts');
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: [
|
||||
@ -146,6 +147,7 @@ const config: StorybookConfig = {
|
||||
'storybook/internal/components': componentsPath,
|
||||
'@storybook/manager-api': managerApiPath,
|
||||
'storybook/internal/manager-api': managerApiPath,
|
||||
'sb-original/image-context': imageContextPath,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 175 KiB |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-a11y",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Test component compliance with web accessibility standards",
|
||||
"keywords": [
|
||||
"a11y",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-actions",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Get UI feedback when an action is performed on an interactive element",
|
||||
"keywords": [
|
||||
"storybook",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-backgrounds",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Switch backgrounds to view components in different settings",
|
||||
"keywords": [
|
||||
"addon",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-controls",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Interact with component inputs dynamically in the Storybook UI",
|
||||
"keywords": [
|
||||
"addon",
|
||||
|
@ -18,7 +18,7 @@ Storybook Docs automatically generates props tables for components in supported
|
||||
|
||||
## Usage
|
||||
|
||||
For framework-specific setup instructions, see the framework's README: [React](../react/README.md), [Vue3 ](../vue3/README.md), [Angular](../angular/README.md), [Web Components](../web-components/README.md), [Ember](../ember/README.md).
|
||||
For framework-specific setup instructions, see the framework's README: [React](../react/README.md), [Vue3](../vue3/README.md), [Angular](../angular/README.md), [Web Components](../web-components/README.md), [Ember](../ember/README.md).
|
||||
|
||||
### DocsPage
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-docs",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Document component usage and properties in Markdown",
|
||||
"keywords": [
|
||||
"addon",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-essentials",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Curated addons to bring out the best of Storybook",
|
||||
"keywords": [
|
||||
"addon",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-mdx-gfm",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "GitHub Flavored Markdown in Storybook",
|
||||
"keywords": [
|
||||
"addon",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-highlight",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Highlight DOM nodes within your stories",
|
||||
"keywords": [
|
||||
"storybook-addons",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-interactions",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Automate, test and debug user interactions",
|
||||
"keywords": [
|
||||
"storybook-addons",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-jest",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "React storybook addon that show component jest report",
|
||||
"keywords": [
|
||||
"addon",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-links",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Link stories together to build demos and prototypes with your UI components",
|
||||
"keywords": [
|
||||
"storybook-addons",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-measure",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Inspect layouts by visualizing the box model",
|
||||
"keywords": [
|
||||
"storybook-addons",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-onboarding",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook Addon Onboarding - Introduces a new onboarding experience",
|
||||
"keywords": [
|
||||
"storybook-addons",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-outline",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Outline all elements with CSS to help with layout placement and alignment",
|
||||
"keywords": [
|
||||
"storybook-addons",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-storysource",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "View a story’s source code to see how it works and paste into your app",
|
||||
"keywords": [
|
||||
"addon",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/experimental-addon-test",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Integrate Vitest with Storybook",
|
||||
"keywords": [
|
||||
"storybook-addons",
|
||||
|
@ -1,76 +0,0 @@
|
||||
import React, {
|
||||
type FC,
|
||||
type SyntheticEvent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { Button, ListItem } from 'storybook/internal/components';
|
||||
import type { TestProviderConfig } from 'storybook/internal/core-events';
|
||||
import { useStorybookApi } from 'storybook/internal/manager-api';
|
||||
import { useTheme } from 'storybook/internal/theming';
|
||||
import { type API_HashEntry, type Addon_TestProviderState } from 'storybook/internal/types';
|
||||
|
||||
import { PlayHollowIcon, StopAltHollowIcon } from '@storybook/icons';
|
||||
|
||||
import { type Config, type Details, TEST_PROVIDER_ID } from '../constants';
|
||||
import { Description } from './Description';
|
||||
import { Title } from './Title';
|
||||
|
||||
export const ContextMenuItem: FC<{
|
||||
context: API_HashEntry;
|
||||
state: TestProviderConfig & Addon_TestProviderState<Details, Config>;
|
||||
}> = ({ context, state }) => {
|
||||
const api = useStorybookApi();
|
||||
const [isDisabled, setDisabled] = useState(false);
|
||||
|
||||
const id = useRef(context.id);
|
||||
id.current = context.id;
|
||||
|
||||
const Icon = state.running ? StopAltHollowIcon : PlayHollowIcon;
|
||||
|
||||
useEffect(() => {
|
||||
setDisabled(false);
|
||||
}, [state.running]);
|
||||
|
||||
const onClick = useCallback(
|
||||
(event: SyntheticEvent) => {
|
||||
setDisabled(true);
|
||||
event.stopPropagation();
|
||||
if (state.running) {
|
||||
api.cancelTestProvider(TEST_PROVIDER_ID);
|
||||
} else {
|
||||
api.runTestProvider(TEST_PROVIDER_ID, { entryId: id.current });
|
||||
}
|
||||
},
|
||||
[api, state.running]
|
||||
);
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={(event) => {
|
||||
// stopPropagation to prevent the parent from closing the context menu, which is the default behavior onClick
|
||||
event.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<ListItem
|
||||
title={<Title state={state} />}
|
||||
center={<Description state={state} />}
|
||||
right={
|
||||
<Button
|
||||
onClick={onClick}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
disabled={state.crashed || isDisabled}
|
||||
>
|
||||
<Icon fill={theme.textMutedColor} />
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -4,6 +4,7 @@ import { Link as LinkComponent } from 'storybook/internal/components';
|
||||
import { type TestProviderConfig, type TestProviderState } from 'storybook/internal/core-events';
|
||||
import { styled } from 'storybook/internal/theming';
|
||||
|
||||
import type { TestResultResult } from '../node/reporter';
|
||||
import { GlobalErrorContext } from './GlobalErrorModal';
|
||||
import { RelativeTime } from './RelativeTime';
|
||||
|
||||
@ -19,11 +20,13 @@ const PositiveText = styled.span(({ theme }) => ({
|
||||
color: theme.color.positiveText,
|
||||
}));
|
||||
|
||||
interface DescriptionProps extends ComponentProps<typeof Wrapper> {
|
||||
interface DescriptionProps extends Omit<ComponentProps<typeof Wrapper>, 'results'> {
|
||||
state: TestProviderConfig & TestProviderState;
|
||||
entryId?: string;
|
||||
results?: TestResultResult[];
|
||||
}
|
||||
|
||||
export function Description({ state, ...props }: DescriptionProps) {
|
||||
export function Description({ state, entryId, results, ...props }: DescriptionProps) {
|
||||
const isMounted = React.useRef(false);
|
||||
const [isUpdated, setUpdated] = React.useState(false);
|
||||
const { setModalOpen } = React.useContext(GlobalErrorContext);
|
||||
@ -48,15 +51,17 @@ export function Description({ state, ...props }: DescriptionProps) {
|
||||
description = state.progress
|
||||
? `Testing... ${state.progress.numPassedTests}/${state.progress.numTotalTests}`
|
||||
: 'Starting...';
|
||||
} else if (entryId && results?.length) {
|
||||
description = `Ran ${results.length} ${results.length === 1 ? 'test' : 'tests'}`;
|
||||
} else if (state.failed && !errorMessage) {
|
||||
description = 'Failed';
|
||||
} else if (state.crashed || (state.failed && errorMessage)) {
|
||||
description = (
|
||||
<>
|
||||
<LinkComponent isButton onClick={() => setModalOpen(true)}>
|
||||
{state.error?.name || 'View full error'}
|
||||
</LinkComponent>
|
||||
</>
|
||||
description = setModalOpen ? (
|
||||
<LinkComponent isButton onClick={() => setModalOpen(true)}>
|
||||
{state.error?.name || 'View full error'}
|
||||
</LinkComponent>
|
||||
) : (
|
||||
state.error?.name || 'Failed'
|
||||
);
|
||||
} else if (state.progress?.finishedAt) {
|
||||
description = (
|
||||
|
@ -23,7 +23,7 @@ const MethodCallWrapper = styled.div(() => ({
|
||||
|
||||
const RowContainer = styled('div', {
|
||||
shouldForwardProp: (prop) => !['call', 'pausedAt'].includes(prop.toString()),
|
||||
})<{ call: Call; pausedAt: Call['id'] }>(
|
||||
})<{ call: Call; pausedAt: Call['id'] | undefined }>(
|
||||
({ theme, call }) => ({
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
@ -117,6 +117,9 @@ const RowMessage = styled('div')(({ theme }) => ({
|
||||
|
||||
export const Exception = ({ exception }: { exception: Call['exception'] }) => {
|
||||
const filter = useAnsiToHtmlFilter();
|
||||
if (!exception) {
|
||||
return null;
|
||||
}
|
||||
if (isJestError(exception)) {
|
||||
return <MatcherResult {...exception} />;
|
||||
}
|
||||
@ -187,7 +190,7 @@ export const Interaction = ({
|
||||
</MethodCallWrapper>
|
||||
</RowLabel>
|
||||
<RowActions>
|
||||
{childCallIds?.length > 0 && (
|
||||
{(childCallIds?.length ?? 0) > 0 && (
|
||||
<WithTooltip
|
||||
hasChrome={false}
|
||||
tooltip={<Note note={`${isCollapsed ? 'Show' : 'Hide'} interactions`} />}
|
||||
|
@ -74,10 +74,10 @@ export const MatcherResult = ({
|
||||
{lines.flatMap((line: string, index: number) => {
|
||||
if (line.startsWith('expect(')) {
|
||||
const received = getParams(line, 7);
|
||||
const remainderIndex = received && 7 + received.length;
|
||||
const remainderIndex = received ? 7 + received.length : 0;
|
||||
const matcher = received && line.slice(remainderIndex).match(/\.(to|last|nth)[A-Z]\w+\(/);
|
||||
if (matcher) {
|
||||
const expectedIndex = remainderIndex + matcher.index + matcher[0].length;
|
||||
const expectedIndex = remainderIndex + (matcher.index ?? 0) + matcher[0].length;
|
||||
const expected = getParams(line, expectedIndex);
|
||||
if (expected) {
|
||||
return [
|
||||
|
@ -139,7 +139,7 @@ export const Node = ({
|
||||
case Object.prototype.hasOwnProperty.call(value, '__class__'):
|
||||
return <ClassNode {...props} {...value.__class__} />;
|
||||
case Object.prototype.hasOwnProperty.call(value, '__callId__'):
|
||||
return <MethodCall call={callsById.get(value.__callId__)} callsById={callsById} />;
|
||||
return <MethodCall call={callsById?.get(value.__callId__)} callsById={callsById} />;
|
||||
/* eslint-enable no-underscore-dangle */
|
||||
|
||||
case Object.prototype.toString.call(value) === '[object Object]':
|
||||
@ -418,7 +418,7 @@ export const MethodCall = ({
|
||||
callsById,
|
||||
}: {
|
||||
call?: Call;
|
||||
callsById: Map<Call['id'], Call>;
|
||||
callsById?: Map<Call['id'], Call>;
|
||||
}) => {
|
||||
// Call might be undefined during initial render, can be safely ignored.
|
||||
if (!call) {
|
||||
@ -434,7 +434,7 @@ export const MethodCall = ({
|
||||
const callId = (elem as CallRef).__callId__;
|
||||
return [
|
||||
callId ? (
|
||||
<MethodCall key={`elem${index}`} call={callsById.get(callId)} callsById={callsById} />
|
||||
<MethodCall key={`elem${index}`} call={callsById?.get(callId)} callsById={callsById} />
|
||||
) : (
|
||||
<span key={`elem${index}`}>{elem as any}</span>
|
||||
),
|
||||
|
@ -22,14 +22,6 @@ import type { API_StatusValue } from '@storybook/types';
|
||||
import { ADDON_ID, STORYBOOK_ADDON_TEST_CHANNEL, TEST_PROVIDER_ID } from '../constants';
|
||||
import { InteractionsPanel } from './InteractionsPanel';
|
||||
|
||||
interface Interaction extends Call {
|
||||
status: Call['status'];
|
||||
childCallIds: Call['id'][];
|
||||
isHidden: boolean;
|
||||
isCollapsed: boolean;
|
||||
toggleCollapsed: () => void;
|
||||
}
|
||||
|
||||
const INITIAL_CONTROL_STATES = {
|
||||
start: false,
|
||||
back: false,
|
||||
@ -60,7 +52,7 @@ export const getInteractions = ({
|
||||
const childCallMap = new Map<Call['id'], Call['id'][]>();
|
||||
|
||||
return log
|
||||
.map<Call & { isHidden: boolean }>(({ callId, ancestors, status }) => {
|
||||
.map(({ callId, ancestors, status }) => {
|
||||
let isHidden = false;
|
||||
ancestors.forEach((ancestor) => {
|
||||
if (collapsed.has(ancestor)) {
|
||||
@ -68,11 +60,12 @@ export const getInteractions = ({
|
||||
}
|
||||
childCallMap.set(ancestor, (childCallMap.get(ancestor) || []).concat(callId));
|
||||
});
|
||||
return { ...calls.get(callId), status, isHidden };
|
||||
return { ...calls.get(callId)!, status, isHidden };
|
||||
})
|
||||
.map<Interaction>((call) => {
|
||||
.map((call) => {
|
||||
const status =
|
||||
call.status === CallStates.ERROR &&
|
||||
call.ancestors &&
|
||||
callsById.get(call.ancestors.slice(-1)[0])?.status === CallStates.ACTIVE
|
||||
? CallStates.ACTIVE
|
||||
: call.status;
|
||||
@ -131,7 +124,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
|
||||
const calls = useRef<Map<Call['id'], Omit<Call, 'status'>>>(new Map());
|
||||
const setCall = ({ status, ...call }: Call) => calls.current.set(call.id, call);
|
||||
|
||||
const endRef = useRef();
|
||||
const endRef = useRef<HTMLDivElement>();
|
||||
useEffect(() => {
|
||||
let observer: IntersectionObserver;
|
||||
if (global.IntersectionObserver) {
|
||||
@ -151,6 +144,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
|
||||
{
|
||||
[EVENTS.CALL]: setCall,
|
||||
[EVENTS.SYNC]: (payload) => {
|
||||
// @ts-expect-error TODO
|
||||
set((s) => {
|
||||
const list = getInteractions({
|
||||
log: payload.logItems,
|
||||
@ -214,6 +208,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// @ts-expect-error TODO
|
||||
set((s) => {
|
||||
const list = getInteractions({
|
||||
log: log.current,
|
||||
@ -250,16 +245,17 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
|
||||
const hasException =
|
||||
!!caughtException ||
|
||||
!!unhandledErrors ||
|
||||
// @ts-expect-error TODO
|
||||
interactions.some((v) => v.status === CallStates.ERROR);
|
||||
|
||||
const storyStatus = storyStatuses[storyId]?.[TEST_PROVIDER_ID];
|
||||
const storyTestStatus = storyStatus?.status;
|
||||
|
||||
const browserTestStatus = useMemo<CallStates | null>(() => {
|
||||
const browserTestStatus = useMemo<CallStates | undefined>(() => {
|
||||
if (!isPlaying && (interactions.length > 0 || hasException)) {
|
||||
return hasException ? CallStates.ERROR : CallStates.DONE;
|
||||
}
|
||||
return isPlaying ? CallStates.ACTIVE : null;
|
||||
return isPlaying ? CallStates.ACTIVE : undefined;
|
||||
}, [isPlaying, interactions, hasException]);
|
||||
|
||||
const { testRunId } = storyStatus?.data || {};
|
||||
@ -315,6 +311,7 @@ export const Panel = memo<{ storyId: string }>(function PanelMemoized({ storyId
|
||||
unhandledErrors={unhandledErrors}
|
||||
isPlaying={isPlaying}
|
||||
pausedAt={pausedAt}
|
||||
// @ts-expect-error TODO
|
||||
endRef={endRef}
|
||||
onScrollToEnd={scrollTarget && scrollToTarget}
|
||||
/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const RelativeTime = ({ timestamp }: { timestamp?: number }) => {
|
||||
const [timeAgo, setTimeAgo] = useState(null);
|
||||
const [timeAgo, setTimeAgo] = useState<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (timestamp) {
|
||||
|
@ -14,7 +14,7 @@ const StyledBadge = styled.div<StatusBadgeProps>(({ theme, status }) => {
|
||||
[CallStates.ERROR]: theme.color.negative,
|
||||
[CallStates.ACTIVE]: theme.color.warning,
|
||||
[CallStates.WAITING]: theme.color.warning,
|
||||
}[status];
|
||||
}[status!];
|
||||
return {
|
||||
padding: '4px 6px 4px 8px;',
|
||||
borderRadius: '4px',
|
||||
@ -36,7 +36,7 @@ export const StatusBadge: React.FC<StatusBadgeProps> = ({ status }) => {
|
||||
[CallStates.ERROR]: 'Fail',
|
||||
[CallStates.ACTIVE]: 'Runs',
|
||||
[CallStates.WAITING]: 'Runs',
|
||||
}[status];
|
||||
}[status!];
|
||||
return (
|
||||
<StyledBadge aria-label="Status of the test run" status={status}>
|
||||
{badgeText}
|
||||
|
@ -109,7 +109,7 @@ const RerunButton = styled(StyledIconButton)<
|
||||
>(({ theme, animating, disabled }) => ({
|
||||
opacity: disabled ? 0.5 : 1,
|
||||
svg: {
|
||||
animation: animating && `${theme.animation.rotate360} 200ms ease-out`,
|
||||
animation: animating ? `${theme.animation.rotate360} 200ms ease-out` : undefined,
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { Link } from 'storybook/internal/components';
|
||||
import { useStorybookApi } from 'storybook/internal/manager-api';
|
||||
import { styled } from 'storybook/internal/theming';
|
||||
import type { StoryId } from 'storybook/internal/types';
|
||||
|
||||
import { CallStates } from '@storybook/instrumenter';
|
||||
|
||||
import { DOCUMENTATION_DISCREPANCY_LINK, STORYBOOK_ADDON_TEST_CHANNEL } from '../constants';
|
||||
import { DOCUMENTATION_DISCREPANCY_LINK } from '../constants';
|
||||
|
||||
const Wrapper = styled.div(({ theme: { color, typography, background } }) => ({
|
||||
textAlign: 'start',
|
||||
@ -32,7 +31,7 @@ const Wrapper = styled.div(({ theme: { color, typography, background } }) => ({
|
||||
}));
|
||||
|
||||
interface TestDiscrepancyMessageProps {
|
||||
browserTestStatus: CallStates;
|
||||
browserTestStatus?: CallStates;
|
||||
}
|
||||
|
||||
export const TestDiscrepancyMessage = ({ browserTestStatus }: TestDiscrepancyMessageProps) => {
|
||||
|
@ -43,7 +43,7 @@ const baseState: TestProviderState<Details, Config> = {
|
||||
cancellable: true,
|
||||
cancelling: false,
|
||||
crashed: false,
|
||||
error: null,
|
||||
error: undefined,
|
||||
failed: false,
|
||||
running: false,
|
||||
watching: false,
|
||||
@ -233,7 +233,7 @@ export const Editing: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const screen = within(canvasElement);
|
||||
|
||||
screen.getByLabelText(/Open settings/).click();
|
||||
screen.getByLabelText(/Show settings/).click();
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
import React, { type ComponentProps, type FC, useCallback, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { Button, ListItem, ProgressSpinner } from 'storybook/internal/components';
|
||||
import {
|
||||
Button,
|
||||
ListItem,
|
||||
ProgressSpinner,
|
||||
TooltipNote,
|
||||
WithTooltip,
|
||||
} from 'storybook/internal/components';
|
||||
import {
|
||||
TESTING_MODULE_CONFIG_CHANGE,
|
||||
type TestProviderConfig,
|
||||
@ -31,7 +37,6 @@ import { type Config, type Details, PANEL_ID } from '../constants';
|
||||
import { type TestStatus } from '../node/reporter';
|
||||
import { Description } from './Description';
|
||||
import { TestStatusIcon } from './TestStatusIcon';
|
||||
import { Title } from './Title';
|
||||
|
||||
const Container = styled.div({
|
||||
display: 'flex',
|
||||
@ -52,6 +57,12 @@ const Info = styled.div({
|
||||
minWidth: 0,
|
||||
});
|
||||
|
||||
const Title = styled.div<{ crashed?: boolean }>(({ crashed, theme }) => ({
|
||||
fontSize: theme.typography.size.s1,
|
||||
fontWeight: crashed ? 'bold' : 'normal',
|
||||
color: crashed ? theme.color.negativeText : theme.color.defaultText,
|
||||
}));
|
||||
|
||||
const Actions = styled.div({
|
||||
display: 'flex',
|
||||
gap: 2,
|
||||
@ -92,7 +103,7 @@ const statusMap: Record<TestStatus, ComponentProps<typeof TestStatusIcon>['statu
|
||||
warning: 'warning',
|
||||
passed: 'positive',
|
||||
skipped: 'unknown',
|
||||
pending: 'unknown',
|
||||
pending: 'pending',
|
||||
};
|
||||
|
||||
export const TestProviderRender: FC<
|
||||
@ -162,7 +173,7 @@ export const TestProviderRender: FC<
|
||||
: undefined;
|
||||
|
||||
const a11ySkippedAmount =
|
||||
state.running || !state?.details.config?.a11y || !state.config.a11y
|
||||
state.running || !state?.details.config?.a11y || !state.config?.a11y
|
||||
? null
|
||||
: a11yResults?.filter((result) => !result).length;
|
||||
|
||||
@ -185,11 +196,7 @@ export const TestProviderRender: FC<
|
||||
})
|
||||
.sort((a, b) => statusOrder.indexOf(a.status) - statusOrder.indexOf(b.status));
|
||||
|
||||
const status = state.running
|
||||
? 'unknown'
|
||||
: state.failed
|
||||
? 'failed'
|
||||
: (results[0]?.status ?? 'unknown');
|
||||
const status = results[0]?.status ?? (state.running ? 'pending' : 'unknown');
|
||||
|
||||
const openPanel = (id: string, panelId: string) => {
|
||||
api.selectStory(id);
|
||||
@ -201,57 +208,90 @@ export const TestProviderRender: FC<
|
||||
<Container {...props}>
|
||||
<Heading>
|
||||
<Info>
|
||||
<Title id="testing-module-title" state={state} />
|
||||
<Description id="testing-module-description" state={state} />
|
||||
<Title id="testing-module-title" crashed={state.crashed}>
|
||||
{state.crashed ? 'Local tests failed' : 'Run local tests'}
|
||||
</Title>
|
||||
<Description
|
||||
id="testing-module-description"
|
||||
state={state}
|
||||
entryId={entryId}
|
||||
results={results}
|
||||
/>
|
||||
</Info>
|
||||
|
||||
<Actions>
|
||||
<Button
|
||||
aria-label={`${isEditing ? 'Close' : 'Open'} settings for ${state.name}`}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
active={isEditing}
|
||||
disabled={state.running && !isEditing}
|
||||
onClick={() => setIsEditing(!isEditing)}
|
||||
>
|
||||
<EditIcon />
|
||||
</Button>
|
||||
{state.watchable && !entryId && (
|
||||
<Button
|
||||
aria-label={`${state.watching ? 'Disable' : 'Enable'} watch mode for ${state.name}`}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
active={state.watching}
|
||||
onClick={() => api.setTestProviderWatchMode(state.id, !state.watching)}
|
||||
disabled={state.running || isEditing}
|
||||
{!entryId && (
|
||||
<WithTooltip
|
||||
hasChrome={false}
|
||||
trigger="hover"
|
||||
tooltip={<TooltipNote note={`${isEditing ? 'Hide' : 'Show'} settings`} />}
|
||||
>
|
||||
<EyeIcon />
|
||||
</Button>
|
||||
<Button
|
||||
aria-label={`${isEditing ? 'Hide' : 'Show'} settings`}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
active={isEditing}
|
||||
disabled={state.running && !isEditing}
|
||||
onClick={() => setIsEditing(!isEditing)}
|
||||
>
|
||||
<EditIcon />
|
||||
</Button>
|
||||
</WithTooltip>
|
||||
)}
|
||||
{!entryId && state.watchable && (
|
||||
<WithTooltip
|
||||
hasChrome={false}
|
||||
trigger="hover"
|
||||
tooltip={<TooltipNote note={`${state.watching ? 'Disable' : 'Enable'} watch mode`} />}
|
||||
>
|
||||
<Button
|
||||
aria-label={`${state.watching ? 'Disable' : 'Enable'} watch mode`}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
active={state.watching}
|
||||
onClick={() => api.setTestProviderWatchMode(state.id, !state.watching)}
|
||||
disabled={state.running || isEditing}
|
||||
>
|
||||
<EyeIcon />
|
||||
</Button>
|
||||
</WithTooltip>
|
||||
)}
|
||||
{state.runnable && (
|
||||
<>
|
||||
{state.running && state.cancellable ? (
|
||||
<Button
|
||||
aria-label={`Stop ${state.name}`}
|
||||
variant="ghost"
|
||||
padding="none"
|
||||
onClick={() => api.cancelTestProvider(state.id)}
|
||||
disabled={state.cancelling}
|
||||
<WithTooltip
|
||||
hasChrome={false}
|
||||
trigger="hover"
|
||||
tooltip={<TooltipNote note="Stop test run" />}
|
||||
>
|
||||
<Progress percentage={state.progress?.percentageCompleted}>
|
||||
<StopIcon />
|
||||
</Progress>
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Stop test run"
|
||||
variant="ghost"
|
||||
padding="none"
|
||||
onClick={() => api.cancelTestProvider(state.id)}
|
||||
disabled={state.cancelling}
|
||||
>
|
||||
<Progress percentage={state.progress?.percentageCompleted}>
|
||||
<StopIcon />
|
||||
</Progress>
|
||||
</Button>
|
||||
</WithTooltip>
|
||||
) : (
|
||||
<Button
|
||||
aria-label={`Start ${state.name}`}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
onClick={() => api.runTestProvider(state.id, { entryId })}
|
||||
disabled={state.running || isEditing}
|
||||
<WithTooltip
|
||||
hasChrome={false}
|
||||
trigger="hover"
|
||||
tooltip={<TooltipNote note="Start test run" />}
|
||||
>
|
||||
<PlayHollowIcon />
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Start test run"
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
onClick={() => api.runTestProvider(state.id, { entryId })}
|
||||
disabled={state.running || isEditing}
|
||||
>
|
||||
<PlayHollowIcon />
|
||||
</Button>
|
||||
</WithTooltip>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@ -266,19 +306,6 @@ export const TestProviderRender: FC<
|
||||
icon={<PointerHandIcon color={theme.textMutedColor} />}
|
||||
right={<Checkbox type="checkbox" checked disabled />}
|
||||
/>
|
||||
<ListItem
|
||||
as="label"
|
||||
title={<ItemTitle enabled={config.coverage}>Coverage</ItemTitle>}
|
||||
icon={<ShieldIcon color={theme.textMutedColor} />}
|
||||
right={
|
||||
<Checkbox
|
||||
type="checkbox"
|
||||
checked={state.watching ? false : config.coverage}
|
||||
disabled={state.watching}
|
||||
onChange={() => updateConfig({ coverage: !config.coverage })}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{isA11yAddon && (
|
||||
<ListItem
|
||||
as="label"
|
||||
@ -293,6 +320,21 @@ export const TestProviderRender: FC<
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{!entryId && (
|
||||
<ListItem
|
||||
as="label"
|
||||
title={<ItemTitle enabled={config.coverage}>Coverage</ItemTitle>}
|
||||
icon={<ShieldIcon color={theme.textMutedColor} />}
|
||||
right={
|
||||
<Checkbox
|
||||
type="checkbox"
|
||||
checked={state.watching ? false : config.coverage}
|
||||
disabled={state.watching}
|
||||
onChange={() => updateConfig({ coverage: !config.coverage })}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Extras>
|
||||
) : (
|
||||
<Extras>
|
||||
@ -304,48 +346,23 @@ export const TestProviderRender: FC<
|
||||
const firstNotPassed = results.find(
|
||||
(r) => r.status === 'failed' || r.status === 'warning'
|
||||
);
|
||||
openPanel(firstNotPassed.storyId, PANEL_ID);
|
||||
if (firstNotPassed) {
|
||||
openPanel(firstNotPassed.storyId, PANEL_ID);
|
||||
}
|
||||
}
|
||||
: null
|
||||
: undefined
|
||||
}
|
||||
icon={
|
||||
state.crashed ? (
|
||||
<TestStatusIcon status="critical" aria-label="status: crashed" />
|
||||
) : status === 'unknown' ? (
|
||||
) : // @ts-expect-error: TODO: Fix types
|
||||
status === 'unknown' ? (
|
||||
<TestStatusIcon status="unknown" aria-label="status: unknown" />
|
||||
) : (
|
||||
<TestStatusIcon status={statusMap[status]} aria-label={`status: ${status}`} />
|
||||
)
|
||||
}
|
||||
/>
|
||||
{coverageSummary ? (
|
||||
<ListItem
|
||||
title={<ItemTitle enabled={config.coverage}>Coverage</ItemTitle>}
|
||||
href={'/coverage/index.html'}
|
||||
// @ts-expect-error ListItem doesn't include all anchor attributes in types, but it is an achor element
|
||||
target="_blank"
|
||||
aria-label="Open coverage report"
|
||||
icon={
|
||||
<TestStatusIcon
|
||||
percentage={coverageSummary.percentage}
|
||||
status={coverageSummary.status}
|
||||
aria-label={`status: ${coverageSummary.status}`}
|
||||
/>
|
||||
}
|
||||
right={
|
||||
coverageSummary.percentage ? (
|
||||
<span aria-label={`${coverageSummary.percentage} percent coverage`}>
|
||||
{coverageSummary.percentage} %
|
||||
</span>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<ListItem
|
||||
title={<ItemTitle enabled={config.coverage}>Coverage</ItemTitle>}
|
||||
icon={<TestStatusIcon status="unknown" aria-label={`status: unknown`} />}
|
||||
/>
|
||||
)}
|
||||
{isA11yAddon && (
|
||||
<ListItem
|
||||
title={<ItemTitle enabled={config.a11y}>Accessibility {a11ySkippedLabel}</ItemTitle>}
|
||||
@ -359,14 +376,48 @@ export const TestProviderRender: FC<
|
||||
(report) => report.status === 'failed' || report.status === 'warning'
|
||||
)
|
||||
);
|
||||
openPanel(firstNotPassed.storyId, A11y_ADDON_PANEL_ID);
|
||||
if (firstNotPassed) {
|
||||
openPanel(firstNotPassed.storyId, A11y_ADDON_PANEL_ID);
|
||||
}
|
||||
}
|
||||
: null
|
||||
: undefined
|
||||
}
|
||||
icon={<TestStatusIcon status={a11yStatus} aria-label={`status: ${a11yStatus}`} />}
|
||||
right={isStoryEntry ? null : a11yNotPassedAmount || null}
|
||||
/>
|
||||
)}
|
||||
{!entryId && (
|
||||
<>
|
||||
{coverageSummary ? (
|
||||
<ListItem
|
||||
title={<ItemTitle enabled={config.coverage}>Coverage</ItemTitle>}
|
||||
href={'/coverage/index.html'}
|
||||
// @ts-expect-error ListItem doesn't include all anchor attributes in types, but it is an achor element
|
||||
target="_blank"
|
||||
aria-label="Open coverage report"
|
||||
icon={
|
||||
<TestStatusIcon
|
||||
percentage={coverageSummary.percentage}
|
||||
status={coverageSummary.status}
|
||||
aria-label={`status: ${coverageSummary.status}`}
|
||||
/>
|
||||
}
|
||||
right={
|
||||
coverageSummary.percentage ? (
|
||||
<span aria-label={`${coverageSummary.percentage} percent coverage`}>
|
||||
{coverageSummary.percentage} %
|
||||
</span>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<ListItem
|
||||
title={<ItemTitle enabled={config.coverage}>Coverage</ItemTitle>}
|
||||
icon={<TestStatusIcon status="unknown" aria-label={`status: unknown`} />}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Extras>
|
||||
)}
|
||||
</Container>
|
||||
|
@ -16,6 +16,12 @@ export const Unknown: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Pending: Story = {
|
||||
args: {
|
||||
status: 'pending',
|
||||
},
|
||||
};
|
||||
|
||||
export const Positive: Story = {
|
||||
args: {
|
||||
status: 'positive',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { styled } from 'storybook/internal/theming';
|
||||
|
||||
export const TestStatusIcon = styled.div<{
|
||||
status: 'positive' | 'warning' | 'negative' | 'critical' | 'unknown';
|
||||
status: 'pending' | 'positive' | 'warning' | 'negative' | 'critical' | 'unknown';
|
||||
percentage?: number;
|
||||
}>(
|
||||
({ percentage }) => ({
|
||||
@ -13,6 +13,12 @@ export const TestStatusIcon = styled.div<{
|
||||
: 'var(--status-color)',
|
||||
borderRadius: '50%',
|
||||
}),
|
||||
({ status, theme }) =>
|
||||
status === 'pending' && {
|
||||
animation: `${theme.animation.glow} 1.5s ease-in-out infinite`,
|
||||
'--status-color': theme.color.mediumdark,
|
||||
'--status-background': `${theme.color.mediumdark}66`,
|
||||
},
|
||||
({ status, theme }) =>
|
||||
status === 'positive' && {
|
||||
'--status-color': theme.color.positive,
|
||||
|
@ -1,21 +0,0 @@
|
||||
import React, { type ComponentProps } from 'react';
|
||||
|
||||
import { type TestProviderConfig, type TestProviderState } from 'storybook/internal/core-events';
|
||||
import { styled } from 'storybook/internal/theming';
|
||||
|
||||
const Wrapper = styled.div<{ crashed?: boolean }>(({ crashed, theme }) => ({
|
||||
fontSize: theme.typography.size.s1,
|
||||
fontWeight: crashed ? 'bold' : 'normal',
|
||||
color: crashed ? theme.color.negativeText : theme.color.defaultText,
|
||||
}));
|
||||
|
||||
export const Title = ({
|
||||
state,
|
||||
...props
|
||||
}: { state: TestProviderConfig & TestProviderState } & ComponentProps<typeof Wrapper>) => {
|
||||
return (
|
||||
<Wrapper crashed={state.crashed} {...props}>
|
||||
{state.crashed || state.failed ? 'Local tests failed' : 'Run local tests'}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
@ -12,6 +12,13 @@ export const DOCUMENTATION_FATAL_ERROR_LINK = `${DOCUMENTATION_LINK}#what-happen
|
||||
|
||||
export const COVERAGE_DIRECTORY = 'coverage';
|
||||
|
||||
export const SUPPORTED_FRAMEWORKS = [
|
||||
'@storybook/nextjs',
|
||||
'@storybook/experimental-nextjs-vite',
|
||||
'@storybook/sveltekit',
|
||||
];
|
||||
|
||||
export const SUPPORTED_RENDERERS = ['@storybook/react', '@storybook/svelte', '@storybook/vue3'];
|
||||
export interface Config {
|
||||
coverage: boolean;
|
||||
a11y: boolean;
|
||||
|
@ -38,6 +38,7 @@ addons.register(ADDON_ID, (api) => {
|
||||
runnable: true,
|
||||
watchable: true,
|
||||
name: 'Component tests',
|
||||
// @ts-expect-error: TODO: Fix types
|
||||
render: (state) => {
|
||||
const [isModalOpen, setModalOpen] = useState(false);
|
||||
return (
|
||||
@ -55,6 +56,7 @@ addons.register(ADDON_ID, (api) => {
|
||||
);
|
||||
},
|
||||
|
||||
// @ts-expect-error: TODO: Fix types
|
||||
sidebarContextMenu: ({ context, state }) => {
|
||||
if (context.type === 'docs') {
|
||||
return null;
|
||||
@ -72,6 +74,7 @@ addons.register(ADDON_ID, (api) => {
|
||||
);
|
||||
},
|
||||
|
||||
// @ts-expect-error: TODO: Fix types
|
||||
stateUpdater: (state, update) => {
|
||||
const updated = {
|
||||
...state,
|
||||
@ -89,6 +92,7 @@ addons.register(ADDON_ID, (api) => {
|
||||
await api.experimental_updateStatus(
|
||||
TEST_PROVIDER_ID,
|
||||
Object.fromEntries(
|
||||
// @ts-expect-error: TODO: Fix types
|
||||
update.details.testResults.flatMap((testResult) =>
|
||||
testResult.results
|
||||
.filter(({ storyId }) => storyId)
|
||||
@ -113,6 +117,7 @@ addons.register(ADDON_ID, (api) => {
|
||||
await api.experimental_updateStatus(
|
||||
'storybook/addon-a11y/test-provider',
|
||||
Object.fromEntries(
|
||||
// @ts-expect-error: TODO: Fix types
|
||||
update.details.testResults.flatMap((testResult) =>
|
||||
testResult.results
|
||||
.filter(({ storyId }) => storyId)
|
||||
@ -143,7 +148,7 @@ addons.register(ADDON_ID, (api) => {
|
||||
|
||||
return updated;
|
||||
},
|
||||
} as Addon_TestProviderType<Details, Config>);
|
||||
} satisfies Omit<Addon_TestProviderType<Details, Config>, 'id'>);
|
||||
}
|
||||
|
||||
const filter = ({ state }: Combo) => {
|
||||
@ -158,7 +163,7 @@ addons.register(ADDON_ID, (api) => {
|
||||
match: ({ viewMode }) => viewMode === 'story',
|
||||
render: ({ active }) => {
|
||||
return (
|
||||
<AddonPanel active={active}>
|
||||
<AddonPanel active={!!active}>
|
||||
<Consumer filter={filter}>{({ storyId }) => <Panel storyId={storyId} />}</Consumer>
|
||||
</AddonPanel>
|
||||
);
|
||||
|
@ -24,7 +24,7 @@ const MAX_START_TIME = 30000;
|
||||
const vitestModulePath = join(__dirname, 'node', 'vitest.mjs');
|
||||
|
||||
// Events that were triggered before Vitest was ready are queued up and resent once it's ready
|
||||
const eventQueue: { type: string; args: any[] }[] = [];
|
||||
const eventQueue: { type: string; args?: any[] }[] = [];
|
||||
|
||||
let child: null | ChildProcess;
|
||||
let ready = false;
|
||||
@ -87,7 +87,7 @@ const bootTestRunner = async (channel: Channel) => {
|
||||
if (result.type === 'ready') {
|
||||
// Resend events that triggered (during) the boot sequence, now that Vitest is ready
|
||||
while (eventQueue.length) {
|
||||
const { type, args } = eventQueue.shift();
|
||||
const { type, args } = eventQueue.shift()!;
|
||||
child?.send({ type, args, from: 'server' });
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ export class StorybookReporter implements Reporter {
|
||||
(t) => t.status === 'failed' && t.results.length === 0
|
||||
);
|
||||
|
||||
const reducedTestSuiteFailures = new Set<string>();
|
||||
const reducedTestSuiteFailures = new Set<string | undefined>();
|
||||
|
||||
testSuiteFailures.forEach((t) => {
|
||||
reducedTestSuiteFailures.add(t.message);
|
||||
@ -240,7 +240,7 @@ export class StorybookReporter implements Reporter {
|
||||
message: Array.from(reducedTestSuiteFailures).reduce(
|
||||
(acc, curr) => `${acc}\n${curr}`,
|
||||
''
|
||||
),
|
||||
)!,
|
||||
}
|
||||
: {
|
||||
name: `${unhandledErrors.length} unhandled error${unhandledErrors?.length > 1 ? 's' : ''}`,
|
||||
|
@ -22,10 +22,11 @@ const vitest = vi.hoisted(() => ({
|
||||
configOverride: {
|
||||
actualTestNamePattern: undefined,
|
||||
get testNamePattern() {
|
||||
return this.actualTestNamePattern;
|
||||
return this.actualTestNamePattern!;
|
||||
},
|
||||
set testNamePattern(value: string) {
|
||||
setTestNamePattern(value);
|
||||
// @ts-expect-error Ignore for testing
|
||||
this.actualTestNamePattern = value;
|
||||
},
|
||||
},
|
||||
|
@ -88,7 +88,7 @@ export class VitestManager {
|
||||
|
||||
try {
|
||||
await this.vitest.init();
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
let message = 'Failed to initialize Vitest';
|
||||
const isV8 = e.message?.includes('@vitest/coverage-v8');
|
||||
const isIstanbul = e.message?.includes('@vitest/coverage-istanbul');
|
||||
@ -148,7 +148,7 @@ export class VitestManager {
|
||||
])) as StoryIndex;
|
||||
const storyIds = requestStoryIds || Object.keys(index.entries);
|
||||
return storyIds.map((id) => index.entries[id]).filter((story) => story.type === 'story');
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
log('Failed to fetch story index: ' + e.message);
|
||||
return [];
|
||||
}
|
||||
@ -316,20 +316,21 @@ export class VitestManager {
|
||||
const id = slash(file);
|
||||
this.vitest?.logger.clearHighlightCache(id);
|
||||
this.updateLastChanged(id);
|
||||
this.storyCountForCurrentRun = 0;
|
||||
|
||||
// when watch mode is disabled, don't trigger any tests (below)
|
||||
// but still invalidate the cache for the changed file, which is handled above
|
||||
if (!this.testManager.config.watchMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.storyCountForCurrentRun = 0;
|
||||
await this.runAffectedTests(file);
|
||||
}
|
||||
|
||||
async registerVitestConfigListener() {
|
||||
this.vitest?.server?.watcher.on('change', async (file) => {
|
||||
file = normalize(file);
|
||||
const isConfig = file === this.vitest.server.config.configFile;
|
||||
const isConfig = file === this.vitest?.server.config.configFile;
|
||||
if (isConfig) {
|
||||
log('Restarting Vitest due to config change');
|
||||
await this.closeVitest();
|
||||
|
@ -25,6 +25,7 @@ import { coerce, satisfies } from 'semver';
|
||||
import { dedent } from 'ts-dedent';
|
||||
|
||||
import { type PostinstallOptions } from '../../../lib/cli-storybook/src/add';
|
||||
import { SUPPORTED_FRAMEWORKS, SUPPORTED_RENDERERS } from './constants';
|
||||
import { printError, printInfo, printSuccess, step } from './postinstall-logger';
|
||||
import { getAddonNames } from './utils';
|
||||
|
||||
@ -55,8 +56,7 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
const allDeps = await packageManager.getAllDependencies();
|
||||
// only install these dependencies if they are not already installed
|
||||
const dependencies = ['vitest', '@vitest/browser', 'playwright'].filter((p) => !allDeps[p]);
|
||||
const vitestVersionSpecifier =
|
||||
allDeps.vitest || (await packageManager.getInstalledVersion('vitest'));
|
||||
const vitestVersionSpecifier = await packageManager.getInstalledVersion('vitest');
|
||||
const coercedVitestVersion = vitestVersionSpecifier ? coerce(vitestVersionSpecifier) : null;
|
||||
// if Vitest is installed, we use the same version to keep consistency across Vitest packages
|
||||
const vitestVersionToInstall = vitestVersionSpecifier ?? 'latest';
|
||||
@ -106,18 +106,11 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
const annotationsImport = [
|
||||
'@storybook/nextjs',
|
||||
'@storybook/experimental-nextjs-vite',
|
||||
'@storybook/sveltekit',
|
||||
].includes(info.frameworkPackageName)
|
||||
const annotationsImport = SUPPORTED_FRAMEWORKS.includes(info.frameworkPackageName)
|
||||
? info.frameworkPackageName === '@storybook/nextjs'
|
||||
? '@storybook/experimental-nextjs-vite'
|
||||
: info.frameworkPackageName
|
||||
: info.rendererPackageName &&
|
||||
['@storybook/react', '@storybook/svelte', '@storybook/vue3'].includes(
|
||||
info.rendererPackageName
|
||||
)
|
||||
: info.rendererPackageName && SUPPORTED_RENDERERS.includes(info.rendererPackageName)
|
||||
? info.rendererPackageName
|
||||
: null;
|
||||
|
||||
@ -152,6 +145,16 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
`);
|
||||
}
|
||||
|
||||
const mswVersionSpecifier = await packageManager.getInstalledVersion('msw');
|
||||
const coercedMswVersion = mswVersionSpecifier ? coerce(mswVersionSpecifier) : null;
|
||||
|
||||
if (coercedMswVersion && !satisfies(coercedMswVersion, '>=2.0.0')) {
|
||||
reasons.push(dedent`
|
||||
• The addon uses Vitest behind the scenes, which supports only version 2 and above of MSW. However, we have detected version ${picocolors.bold(coercedMswVersion.version)} in this project.
|
||||
Please update the 'msw' package and try again.
|
||||
`);
|
||||
}
|
||||
|
||||
if (info.frameworkPackageName === '@storybook/nextjs') {
|
||||
const nextVersion = await packageManager.getInstalledVersion('next');
|
||||
if (!nextVersion) {
|
||||
@ -166,6 +169,7 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
reasons.unshift(
|
||||
`Storybook Test's automated setup failed due to the following package incompatibilities:`
|
||||
);
|
||||
reasons.push('--------------------------------');
|
||||
reasons.push(
|
||||
dedent`
|
||||
You can fix these issues and rerun the command to reinstall. If you wish to roll back the installation, remove ${picocolors.bold(colors.pink(ADDON_NAME))} from the "addons" array
|
||||
@ -177,14 +181,14 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
reasons.push(
|
||||
dedent`
|
||||
Please check the documentation for more information about its requirements and installation:
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/vitest-plugin`)}
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/test-addon`)}
|
||||
`
|
||||
);
|
||||
} else {
|
||||
reasons.push(
|
||||
dedent`
|
||||
Fear not, however, you can follow the manual installation process instead at:
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/vitest-plugin#manual`)}
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/test-addon#manual-setup`)}
|
||||
`
|
||||
);
|
||||
}
|
||||
@ -306,7 +310,7 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
${colors.gray(vitestSetupFile)}
|
||||
|
||||
Please refer to the documentation to complete the setup manually:
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/vitest-plugin#manual`)}
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/test-addon#manual-setup`)}
|
||||
`
|
||||
);
|
||||
logger.line(1);
|
||||
@ -366,7 +370,7 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
your existing workspace file automatically, you must do it yourself. This was the last step.
|
||||
|
||||
Please refer to the documentation to complete the setup manually:
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/vitest-plugin#manual`)}
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/test-addon#manual-setup`)}
|
||||
`
|
||||
);
|
||||
logger.line(1);
|
||||
@ -382,13 +386,13 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
'🚨 Oh no!',
|
||||
dedent`
|
||||
You seem to have an existing test configuration in your Vite config file:
|
||||
${colors.gray(vitestWorkspaceFile || '')}
|
||||
${colors.gray(viteConfigFile || '')}
|
||||
|
||||
I was able to configure most of the addon but could not safely extend
|
||||
your existing workspace file automatically, you must do it yourself. This was the last step.
|
||||
|
||||
Please refer to the documentation to complete the setup manually:
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/vitest-plugin#manual`)}
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/test-addon#manual-setup`)}
|
||||
`
|
||||
);
|
||||
logger.line(1);
|
||||
@ -414,14 +418,14 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
import { defineWorkspace } from 'vitest/config';
|
||||
import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin';
|
||||
|
||||
// More info at: https://storybook.js.org/docs/writing-tests/vitest-plugin
|
||||
// More info at: https://storybook.js.org/docs/writing-tests/test-addon
|
||||
export default defineWorkspace([
|
||||
'${relative(dirname(browserWorkspaceFile), rootConfig)}',
|
||||
{
|
||||
extends: '${viteConfigFile ? relative(dirname(browserWorkspaceFile), viteConfigFile) : ''}',
|
||||
plugins: [
|
||||
// The plugin will run tests for the stories defined in your Storybook config
|
||||
// See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest
|
||||
// See options at: https://storybook.js.org/docs/writing-tests/test-addon#storybooktest
|
||||
storybookTest({ configDir: '${options.configDir}' }),
|
||||
],
|
||||
test: {
|
||||
@ -454,11 +458,11 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin';
|
||||
|
||||
// More info at: https://storybook.js.org/docs/writing-tests/vitest-plugin
|
||||
// More info at: https://storybook.js.org/docs/writing-tests/test-addon
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
// The plugin will run tests for the stories defined in your Storybook config
|
||||
// See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest
|
||||
// See options at: https://storybook.js.org/docs/writing-tests/test-addon#storybooktest
|
||||
storybookTest({ configDir: '${options.configDir}' }),
|
||||
],
|
||||
test: {
|
||||
@ -488,7 +492,7 @@ export default async function postInstall(options: PostinstallOptions) {
|
||||
• When using the Vitest extension in your editor, all of your stories will be shown as tests!
|
||||
|
||||
Check the documentation for more information about its features and options at:
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/vitest-plugin`)}
|
||||
${picocolors.cyan(`https://storybook.js.org/docs/writing-tests/test-addon`)}
|
||||
`
|
||||
);
|
||||
logger.line(1);
|
||||
|
@ -74,13 +74,15 @@ export const teardown = async () => {
|
||||
logger.verbose('Stopping Storybook process');
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
// Storybook starts multiple child processes, so we need to kill the whole tree
|
||||
treeKill(storybookProcess.pid, 'SIGTERM', (error) => {
|
||||
if (error) {
|
||||
logger.error('Failed to stop Storybook process:');
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
if (storybookProcess?.pid) {
|
||||
treeKill(storybookProcess.pid, 'SIGTERM', (error) => {
|
||||
if (error) {
|
||||
logger.error('Failed to stop Storybook process:');
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -209,6 +209,7 @@ export const storybookTest = async (options?: UserOptions): Promise<Plugin[]> =>
|
||||
}
|
||||
: {}),
|
||||
|
||||
// @ts-expect-error: TODO
|
||||
browser: {
|
||||
...inputConfig_ONLY_MUTATE_WHEN_STRICTLY_NEEDED_OR_YOU_WILL_BE_FIRED.test?.browser,
|
||||
commands: {
|
||||
@ -284,9 +285,11 @@ export const storybookTest = async (options?: UserOptions): Promise<Plugin[]> =>
|
||||
|
||||
// alert the user of problems
|
||||
if (
|
||||
inputConfig_ONLY_MUTATE_WHEN_STRICTLY_NEEDED_OR_YOU_WILL_BE_FIRED.test.include?.length > 0
|
||||
(inputConfig_ONLY_MUTATE_WHEN_STRICTLY_NEEDED_OR_YOU_WILL_BE_FIRED.test?.include?.length ??
|
||||
0) > 0
|
||||
) {
|
||||
// remove the user's existing include, because we're replacing it with our own heuristic based on main.ts#stories
|
||||
// @ts-expect-error: Ignore
|
||||
inputConfig_ONLY_MUTATE_WHEN_STRICTLY_NEEDED_OR_YOU_WILL_BE_FIRED.test.include = [];
|
||||
console.log(
|
||||
picocolors.yellow(dedent`
|
||||
@ -303,19 +306,21 @@ export const storybookTest = async (options?: UserOptions): Promise<Plugin[]> =>
|
||||
return config;
|
||||
},
|
||||
async configureServer(server) {
|
||||
for (const staticDir of staticDirs) {
|
||||
try {
|
||||
const { staticPath, targetEndpoint } = mapStaticDir(staticDir, directories.configDir);
|
||||
server.middlewares.use(
|
||||
targetEndpoint,
|
||||
sirv(staticPath, {
|
||||
dev: true,
|
||||
etag: true,
|
||||
extensions: [],
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
if (staticDirs) {
|
||||
for (const staticDir of staticDirs) {
|
||||
try {
|
||||
const { staticPath, targetEndpoint } = mapStaticDir(staticDir, directories.configDir);
|
||||
server.middlewares.use(
|
||||
targetEndpoint,
|
||||
sirv(staticPath, {
|
||||
dev: true,
|
||||
etag: true,
|
||||
extensions: [],
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -85,7 +85,7 @@ export const setViewport = async (parameters: Parameters = {}, globals: Globals
|
||||
let viewportWidth = DEFAULT_VIEWPORT_DIMENSIONS.width;
|
||||
let viewportHeight = DEFAULT_VIEWPORT_DIMENSIONS.height;
|
||||
|
||||
if (defaultViewport in viewports) {
|
||||
if (defaultViewport && defaultViewport in viewports) {
|
||||
const styles = viewports[defaultViewport].styles as ViewportStyles;
|
||||
if (styles?.width && styles?.height) {
|
||||
const { width, height } = styles;
|
||||
|
@ -5,7 +5,7 @@
|
||||
"module": "Preserve",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["vitest"],
|
||||
"strict": false
|
||||
"strict": true
|
||||
},
|
||||
"include": ["src/**/*", "./typings.d.ts"]
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-themes",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Switch between multiple themes for you components in Storybook",
|
||||
"keywords": [
|
||||
"css",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-toolbars",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Create your own toolbar items that control story rendering",
|
||||
"keywords": [
|
||||
"addon",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-viewport",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Build responsive components by adjusting Storybook’s viewport size and orientation",
|
||||
"keywords": [
|
||||
"addon",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/builder-vite",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "A plugin to run and build Storybooks with Vite",
|
||||
"homepage": "https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme",
|
||||
"bugs": {
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { toImportFn } from './codegen-importfn-script';
|
||||
|
||||
describe('toImportFn', () => {
|
||||
it('should correctly map story paths to import functions for absolute paths on Linux', async () => {
|
||||
const root = '/absolute/path';
|
||||
vi.spyOn(process, 'cwd').mockReturnValue('/absolute/path');
|
||||
|
||||
const stories = ['/absolute/path/to/story1.js', '/absolute/path/to/story2.js'];
|
||||
|
||||
const result = await toImportFn(root, stories);
|
||||
const result = await toImportFn(stories);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"const importers = {
|
||||
@ -22,10 +23,10 @@ describe('toImportFn', () => {
|
||||
});
|
||||
|
||||
it('should correctly map story paths to import functions for absolute paths on Windows', async () => {
|
||||
const root = 'C:\\absolute\\path';
|
||||
vi.spyOn(process, 'cwd').mockReturnValue('C:\\absolute\\path');
|
||||
const stories = ['C:\\absolute\\path\\to\\story1.js', 'C:\\absolute\\path\\to\\story2.js'];
|
||||
|
||||
const result = await toImportFn(root, stories);
|
||||
const result = await toImportFn(stories);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"const importers = {
|
||||
@ -43,7 +44,7 @@ describe('toImportFn', () => {
|
||||
const root = '/absolute/path';
|
||||
const stories: string[] = [];
|
||||
|
||||
const result = await toImportFn(root, stories);
|
||||
const result = await toImportFn(stories);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"const importers = {};
|
||||
|
@ -29,9 +29,9 @@ function toImportPath(relativePath: string) {
|
||||
*
|
||||
* @param stories An array of absolute story paths.
|
||||
*/
|
||||
export async function toImportFn(root: string, stories: string[]) {
|
||||
export async function toImportFn(stories: string[]) {
|
||||
const objectEntries = stories.map((file) => {
|
||||
const relativePath = relative(root, file);
|
||||
const relativePath = relative(process.cwd(), file);
|
||||
|
||||
return [toImportPath(relativePath), genDynamicImport(normalize(file))] as [string, string];
|
||||
});
|
||||
@ -51,5 +51,5 @@ export async function generateImportFnScriptCode(options: Options): Promise<stri
|
||||
|
||||
// We can then call toImportFn to create a function that can be used to load each story dynamically.
|
||||
// eslint-disable-next-line @typescript-eslint/return-await
|
||||
return await toImportFn(options.projectRoot || process.cwd(), stories);
|
||||
return await toImportFn(stories);
|
||||
}
|
||||
|
@ -13,16 +13,58 @@ const INCLUDE_CANDIDATES = [
|
||||
'@emotion/core',
|
||||
'@emotion/is-prop-valid',
|
||||
'@emotion/styled',
|
||||
'@storybook/addon-a11y/preview',
|
||||
'@storybook/addon-backgrounds/preview',
|
||||
'@storybook/addon-designs/blocks',
|
||||
'@storybook/addon-docs/preview',
|
||||
'@storybook/addon-essentials/actions/preview',
|
||||
'@storybook/addon-essentials/actions/preview',
|
||||
'@storybook/addon-essentials/backgrounds/preview',
|
||||
'@storybook/addon-essentials/docs/preview',
|
||||
'@storybook/addon-essentials/highlight/preview',
|
||||
'@storybook/addon-essentials/measure/preview',
|
||||
'@storybook/addon-essentials/outline/preview',
|
||||
'@storybook/addon-essentials/viewport/preview',
|
||||
'@storybook/addon-highlight/preview',
|
||||
'@storybook/addon-links/preview',
|
||||
'@storybook/addon-measure/preview',
|
||||
'@storybook/addon-outline/preview',
|
||||
'@storybook/addon-themes',
|
||||
'@storybook/addon-themes/preview',
|
||||
'@storybook/addon-viewport',
|
||||
'@storybook/addon-viewport/preview',
|
||||
'@storybook/blocks',
|
||||
'@storybook/components',
|
||||
'@storybook/experimental-addon-test/preview',
|
||||
'@storybook/experimental-nextjs-vite/dist/preview.mjs',
|
||||
'@storybook/html',
|
||||
'@storybook/html/dist/entry-preview-docs.mjs',
|
||||
'@storybook/html/dist/entry-preview.mjs',
|
||||
'@storybook/preact',
|
||||
'@storybook/preact/dist/entry-preview-docs.mjs',
|
||||
'@storybook/preact/dist/entry-preview.mjs',
|
||||
'@storybook/react > acorn-jsx',
|
||||
'@storybook/react',
|
||||
'@storybook/react/dist/entry-preview-docs.mjs',
|
||||
'@storybook/react/dist/entry-preview-rsc.mjs',
|
||||
'@storybook/react/dist/entry-preview.mjs',
|
||||
'@storybook/svelte',
|
||||
'@storybook/svelte/dist/entry-preview-docs.mjs',
|
||||
'@storybook/svelte/dist/entry-preview.mjs',
|
||||
'@storybook/theming',
|
||||
'@storybook/vue3',
|
||||
'@storybook/vue3/dist/entry-preview-docs.mjs',
|
||||
'@storybook/vue3/dist/entry-preview.mjs',
|
||||
'@storybook/web-components',
|
||||
'@storybook/web-components/dist/entry-preview-docs.mjs',
|
||||
'@storybook/web-components/dist/entry-preview.mjs',
|
||||
'acorn-jsx',
|
||||
'acorn-walk',
|
||||
'acorn',
|
||||
'airbnb-js-shims',
|
||||
'ansi-to-html',
|
||||
'axe-core',
|
||||
'chromatic/isChromatic',
|
||||
'color-convert',
|
||||
'deep-object-diff',
|
||||
'doctrine',
|
||||
@ -73,6 +115,8 @@ const INCLUDE_CANDIDATES = [
|
||||
'lodash/upperFirst.js',
|
||||
'lodash/upperFirst',
|
||||
'memoizerific',
|
||||
'mockdate',
|
||||
'msw-storybook-addon',
|
||||
'overlayscrollbars',
|
||||
'polished',
|
||||
'prettier/parser-babel',
|
||||
@ -100,8 +144,11 @@ const INCLUDE_CANDIDATES = [
|
||||
'refractor/lang/typescript.js',
|
||||
'refractor/lang/yaml.js',
|
||||
'regenerator-runtime/runtime.js',
|
||||
'sb-original/default-loader',
|
||||
'sb-original/image-context',
|
||||
'slash',
|
||||
'store2',
|
||||
'storybook/internal/preview/runtime',
|
||||
'synchronous-promise',
|
||||
'telejson',
|
||||
'ts-dedent',
|
||||
|
@ -53,18 +53,18 @@ export async function commonConfig(
|
||||
|
||||
const { viteConfigPath } = await getBuilderOptions<BuilderOptions>(options);
|
||||
|
||||
options.projectRoot = options.projectRoot || resolve(options.configDir, '..');
|
||||
const projectRoot = resolve(options.configDir, '..');
|
||||
|
||||
// I destructure away the `build` property from the user's config object
|
||||
// I do this because I can contain config that breaks storybook, such as we had in a lit project.
|
||||
// If the user needs to configure the `build` they need to do so in the viteFinal function in main.js.
|
||||
const { config: { build: buildProperty = undefined, ...userConfig } = {} } =
|
||||
(await loadConfigFromFile(configEnv, viteConfigPath, options.projectRoot)) ?? {};
|
||||
(await loadConfigFromFile(configEnv, viteConfigPath, projectRoot)) ?? {};
|
||||
|
||||
const sbConfig: InlineConfig = {
|
||||
configFile: false,
|
||||
cacheDir: resolvePathInStorybookCache('sb-vite', options.cacheKey),
|
||||
root: options.projectRoot,
|
||||
root: projectRoot,
|
||||
// Allow storybook deployed as subfolder. See https://github.com/storybookjs/builder-vite/issues/238
|
||||
base: './',
|
||||
plugins: await pluginConfig(options),
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/builder-webpack5",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook framework-agnostic API",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -64,7 +64,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/core-webpack": "workspace:*",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/semver": "^7.3.4",
|
||||
"browser-assert": "^1.2.1",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
||||
@ -90,6 +89,7 @@
|
||||
"webpack-virtual-modules": "^0.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/pretty-hrtime": "^1.0.0",
|
||||
"@types/terser-webpack-plugin": "^5.2.0",
|
||||
"@types/webpack-hot-middleware": "^2.25.6",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/core",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook framework-agnostic API",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,88 +1,88 @@
|
||||
// auto generated file, do not edit
|
||||
export default {
|
||||
'@storybook/addon-a11y': '8.5.0-beta.4',
|
||||
'@storybook/addon-actions': '8.5.0-beta.4',
|
||||
'@storybook/addon-backgrounds': '8.5.0-beta.4',
|
||||
'@storybook/addon-controls': '8.5.0-beta.4',
|
||||
'@storybook/addon-docs': '8.5.0-beta.4',
|
||||
'@storybook/addon-essentials': '8.5.0-beta.4',
|
||||
'@storybook/addon-mdx-gfm': '8.5.0-beta.4',
|
||||
'@storybook/addon-highlight': '8.5.0-beta.4',
|
||||
'@storybook/addon-interactions': '8.5.0-beta.4',
|
||||
'@storybook/addon-jest': '8.5.0-beta.4',
|
||||
'@storybook/addon-links': '8.5.0-beta.4',
|
||||
'@storybook/addon-measure': '8.5.0-beta.4',
|
||||
'@storybook/addon-onboarding': '8.5.0-beta.4',
|
||||
'@storybook/addon-outline': '8.5.0-beta.4',
|
||||
'@storybook/addon-storysource': '8.5.0-beta.4',
|
||||
'@storybook/experimental-addon-test': '8.5.0-beta.4',
|
||||
'@storybook/addon-themes': '8.5.0-beta.4',
|
||||
'@storybook/addon-toolbars': '8.5.0-beta.4',
|
||||
'@storybook/addon-viewport': '8.5.0-beta.4',
|
||||
'@storybook/builder-vite': '8.5.0-beta.4',
|
||||
'@storybook/builder-webpack5': '8.5.0-beta.4',
|
||||
'@storybook/core': '8.5.0-beta.4',
|
||||
'@storybook/builder-manager': '8.5.0-beta.4',
|
||||
'@storybook/channels': '8.5.0-beta.4',
|
||||
'@storybook/client-logger': '8.5.0-beta.4',
|
||||
'@storybook/components': '8.5.0-beta.4',
|
||||
'@storybook/core-common': '8.5.0-beta.4',
|
||||
'@storybook/core-events': '8.5.0-beta.4',
|
||||
'@storybook/core-server': '8.5.0-beta.4',
|
||||
'@storybook/csf-tools': '8.5.0-beta.4',
|
||||
'@storybook/docs-tools': '8.5.0-beta.4',
|
||||
'@storybook/manager': '8.5.0-beta.4',
|
||||
'@storybook/manager-api': '8.5.0-beta.4',
|
||||
'@storybook/node-logger': '8.5.0-beta.4',
|
||||
'@storybook/preview': '8.5.0-beta.4',
|
||||
'@storybook/preview-api': '8.5.0-beta.4',
|
||||
'@storybook/router': '8.5.0-beta.4',
|
||||
'@storybook/telemetry': '8.5.0-beta.4',
|
||||
'@storybook/theming': '8.5.0-beta.4',
|
||||
'@storybook/types': '8.5.0-beta.4',
|
||||
'@storybook/angular': '8.5.0-beta.4',
|
||||
'@storybook/ember': '8.5.0-beta.4',
|
||||
'@storybook/experimental-nextjs-vite': '8.5.0-beta.4',
|
||||
'@storybook/html-vite': '8.5.0-beta.4',
|
||||
'@storybook/html-webpack5': '8.5.0-beta.4',
|
||||
'@storybook/nextjs': '8.5.0-beta.4',
|
||||
'@storybook/preact-vite': '8.5.0-beta.4',
|
||||
'@storybook/preact-webpack5': '8.5.0-beta.4',
|
||||
'@storybook/react-native-web-vite': '8.5.0-beta.4',
|
||||
'@storybook/react-vite': '8.5.0-beta.4',
|
||||
'@storybook/react-webpack5': '8.5.0-beta.4',
|
||||
'@storybook/server-webpack5': '8.5.0-beta.4',
|
||||
'@storybook/svelte-vite': '8.5.0-beta.4',
|
||||
'@storybook/svelte-webpack5': '8.5.0-beta.4',
|
||||
'@storybook/sveltekit': '8.5.0-beta.4',
|
||||
'@storybook/vue3-vite': '8.5.0-beta.4',
|
||||
'@storybook/vue3-webpack5': '8.5.0-beta.4',
|
||||
'@storybook/web-components-vite': '8.5.0-beta.4',
|
||||
'@storybook/web-components-webpack5': '8.5.0-beta.4',
|
||||
'@storybook/blocks': '8.5.0-beta.4',
|
||||
storybook: '8.5.0-beta.4',
|
||||
sb: '8.5.0-beta.4',
|
||||
'@storybook/cli': '8.5.0-beta.4',
|
||||
'@storybook/codemod': '8.5.0-beta.4',
|
||||
'@storybook/core-webpack': '8.5.0-beta.4',
|
||||
'create-storybook': '8.5.0-beta.4',
|
||||
'@storybook/csf-plugin': '8.5.0-beta.4',
|
||||
'@storybook/instrumenter': '8.5.0-beta.4',
|
||||
'@storybook/react-dom-shim': '8.5.0-beta.4',
|
||||
'@storybook/source-loader': '8.5.0-beta.4',
|
||||
'@storybook/test': '8.5.0-beta.4',
|
||||
'@storybook/preset-create-react-app': '8.5.0-beta.4',
|
||||
'@storybook/preset-html-webpack': '8.5.0-beta.4',
|
||||
'@storybook/preset-preact-webpack': '8.5.0-beta.4',
|
||||
'@storybook/preset-react-webpack': '8.5.0-beta.4',
|
||||
'@storybook/preset-server-webpack': '8.5.0-beta.4',
|
||||
'@storybook/preset-svelte-webpack': '8.5.0-beta.4',
|
||||
'@storybook/preset-vue3-webpack': '8.5.0-beta.4',
|
||||
'@storybook/html': '8.5.0-beta.4',
|
||||
'@storybook/preact': '8.5.0-beta.4',
|
||||
'@storybook/react': '8.5.0-beta.4',
|
||||
'@storybook/server': '8.5.0-beta.4',
|
||||
'@storybook/svelte': '8.5.0-beta.4',
|
||||
'@storybook/vue3': '8.5.0-beta.4',
|
||||
'@storybook/web-components': '8.5.0-beta.4',
|
||||
'@storybook/addon-a11y': '8.5.0-beta.7',
|
||||
'@storybook/addon-actions': '8.5.0-beta.7',
|
||||
'@storybook/addon-backgrounds': '8.5.0-beta.7',
|
||||
'@storybook/addon-controls': '8.5.0-beta.7',
|
||||
'@storybook/addon-docs': '8.5.0-beta.7',
|
||||
'@storybook/addon-essentials': '8.5.0-beta.7',
|
||||
'@storybook/addon-mdx-gfm': '8.5.0-beta.7',
|
||||
'@storybook/addon-highlight': '8.5.0-beta.7',
|
||||
'@storybook/addon-interactions': '8.5.0-beta.7',
|
||||
'@storybook/addon-jest': '8.5.0-beta.7',
|
||||
'@storybook/addon-links': '8.5.0-beta.7',
|
||||
'@storybook/addon-measure': '8.5.0-beta.7',
|
||||
'@storybook/addon-onboarding': '8.5.0-beta.7',
|
||||
'@storybook/addon-outline': '8.5.0-beta.7',
|
||||
'@storybook/addon-storysource': '8.5.0-beta.7',
|
||||
'@storybook/experimental-addon-test': '8.5.0-beta.7',
|
||||
'@storybook/addon-themes': '8.5.0-beta.7',
|
||||
'@storybook/addon-toolbars': '8.5.0-beta.7',
|
||||
'@storybook/addon-viewport': '8.5.0-beta.7',
|
||||
'@storybook/builder-vite': '8.5.0-beta.7',
|
||||
'@storybook/builder-webpack5': '8.5.0-beta.7',
|
||||
'@storybook/core': '8.5.0-beta.7',
|
||||
'@storybook/builder-manager': '8.5.0-beta.7',
|
||||
'@storybook/channels': '8.5.0-beta.7',
|
||||
'@storybook/client-logger': '8.5.0-beta.7',
|
||||
'@storybook/components': '8.5.0-beta.7',
|
||||
'@storybook/core-common': '8.5.0-beta.7',
|
||||
'@storybook/core-events': '8.5.0-beta.7',
|
||||
'@storybook/core-server': '8.5.0-beta.7',
|
||||
'@storybook/csf-tools': '8.5.0-beta.7',
|
||||
'@storybook/docs-tools': '8.5.0-beta.7',
|
||||
'@storybook/manager': '8.5.0-beta.7',
|
||||
'@storybook/manager-api': '8.5.0-beta.7',
|
||||
'@storybook/node-logger': '8.5.0-beta.7',
|
||||
'@storybook/preview': '8.5.0-beta.7',
|
||||
'@storybook/preview-api': '8.5.0-beta.7',
|
||||
'@storybook/router': '8.5.0-beta.7',
|
||||
'@storybook/telemetry': '8.5.0-beta.7',
|
||||
'@storybook/theming': '8.5.0-beta.7',
|
||||
'@storybook/types': '8.5.0-beta.7',
|
||||
'@storybook/angular': '8.5.0-beta.7',
|
||||
'@storybook/ember': '8.5.0-beta.7',
|
||||
'@storybook/experimental-nextjs-vite': '8.5.0-beta.7',
|
||||
'@storybook/html-vite': '8.5.0-beta.7',
|
||||
'@storybook/html-webpack5': '8.5.0-beta.7',
|
||||
'@storybook/nextjs': '8.5.0-beta.7',
|
||||
'@storybook/preact-vite': '8.5.0-beta.7',
|
||||
'@storybook/preact-webpack5': '8.5.0-beta.7',
|
||||
'@storybook/react-native-web-vite': '8.5.0-beta.7',
|
||||
'@storybook/react-vite': '8.5.0-beta.7',
|
||||
'@storybook/react-webpack5': '8.5.0-beta.7',
|
||||
'@storybook/server-webpack5': '8.5.0-beta.7',
|
||||
'@storybook/svelte-vite': '8.5.0-beta.7',
|
||||
'@storybook/svelte-webpack5': '8.5.0-beta.7',
|
||||
'@storybook/sveltekit': '8.5.0-beta.7',
|
||||
'@storybook/vue3-vite': '8.5.0-beta.7',
|
||||
'@storybook/vue3-webpack5': '8.5.0-beta.7',
|
||||
'@storybook/web-components-vite': '8.5.0-beta.7',
|
||||
'@storybook/web-components-webpack5': '8.5.0-beta.7',
|
||||
'@storybook/blocks': '8.5.0-beta.7',
|
||||
storybook: '8.5.0-beta.7',
|
||||
sb: '8.5.0-beta.7',
|
||||
'@storybook/cli': '8.5.0-beta.7',
|
||||
'@storybook/codemod': '8.5.0-beta.7',
|
||||
'@storybook/core-webpack': '8.5.0-beta.7',
|
||||
'create-storybook': '8.5.0-beta.7',
|
||||
'@storybook/csf-plugin': '8.5.0-beta.7',
|
||||
'@storybook/instrumenter': '8.5.0-beta.7',
|
||||
'@storybook/react-dom-shim': '8.5.0-beta.7',
|
||||
'@storybook/source-loader': '8.5.0-beta.7',
|
||||
'@storybook/test': '8.5.0-beta.7',
|
||||
'@storybook/preset-create-react-app': '8.5.0-beta.7',
|
||||
'@storybook/preset-html-webpack': '8.5.0-beta.7',
|
||||
'@storybook/preset-preact-webpack': '8.5.0-beta.7',
|
||||
'@storybook/preset-react-webpack': '8.5.0-beta.7',
|
||||
'@storybook/preset-server-webpack': '8.5.0-beta.7',
|
||||
'@storybook/preset-svelte-webpack': '8.5.0-beta.7',
|
||||
'@storybook/preset-vue3-webpack': '8.5.0-beta.7',
|
||||
'@storybook/html': '8.5.0-beta.7',
|
||||
'@storybook/preact': '8.5.0-beta.7',
|
||||
'@storybook/react': '8.5.0-beta.7',
|
||||
'@storybook/server': '8.5.0-beta.7',
|
||||
'@storybook/svelte': '8.5.0-beta.7',
|
||||
'@storybook/vue3': '8.5.0-beta.7',
|
||||
'@storybook/web-components': '8.5.0-beta.7',
|
||||
};
|
||||
|
@ -1 +1 @@
|
||||
export const version = '8.5.0-beta.4';
|
||||
export const version = '8.5.0-beta.7';
|
||||
|
@ -22,6 +22,7 @@ const empty = {
|
||||
const PositionedWithTooltip = styled(WithTooltip)({
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
zIndex: 1,
|
||||
});
|
||||
|
||||
const FloatingStatusButton = styled(StatusButton)({
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Button, ProgressSpinner } from '@storybook/core/components';
|
||||
import { Button, ProgressSpinner, TooltipNote, WithTooltip } from '@storybook/core/components';
|
||||
import { styled } from '@storybook/core/theming';
|
||||
import { EyeIcon, PlayHollowIcon, StopAltIcon } from '@storybook/icons';
|
||||
|
||||
@ -61,46 +61,68 @@ export const LegacyRender = ({ ...state }: TestProviders[keyof TestProviders]) =
|
||||
|
||||
<Actions>
|
||||
{state.watchable && (
|
||||
<Button
|
||||
aria-label={`${state.watching ? 'Disable' : 'Enable'} watch mode for ${name}`}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
active={state.watching}
|
||||
onClick={() => api.setTestProviderWatchMode(state.id, !state.watching)}
|
||||
disabled={state.crashed || state.running}
|
||||
<WithTooltip
|
||||
hasChrome={false}
|
||||
trigger="hover"
|
||||
tooltip={
|
||||
<TooltipNote
|
||||
note={`${state.watching ? 'Disable' : 'Enable'} watch mode for ${state.name}`}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EyeIcon />
|
||||
</Button>
|
||||
<Button
|
||||
aria-label={`${state.watching ? 'Disable' : 'Enable'} watch mode for ${state.name}`}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
active={state.watching}
|
||||
onClick={() => api.setTestProviderWatchMode(state.id, !state.watching)}
|
||||
disabled={state.crashed || state.running}
|
||||
>
|
||||
<EyeIcon />
|
||||
</Button>
|
||||
</WithTooltip>
|
||||
)}
|
||||
{state.runnable && (
|
||||
<>
|
||||
{state.running && state.cancellable ? (
|
||||
<Button
|
||||
aria-label={`Stop ${name}`}
|
||||
variant="ghost"
|
||||
padding="none"
|
||||
onClick={() => api.cancelTestProvider(state.id)}
|
||||
disabled={state.cancelling}
|
||||
<WithTooltip
|
||||
hasChrome={false}
|
||||
trigger="hover"
|
||||
tooltip={<TooltipNote note={`Stop ${state.name}`} />}
|
||||
>
|
||||
<Progress
|
||||
percentage={
|
||||
state.progress?.percentageCompleted ??
|
||||
(state.details as any)?.buildProgressPercentage
|
||||
}
|
||||
<Button
|
||||
aria-label={`Stop ${state.name}`}
|
||||
variant="ghost"
|
||||
padding="none"
|
||||
onClick={() => api.cancelTestProvider(state.id)}
|
||||
disabled={state.cancelling}
|
||||
>
|
||||
<StopIcon />
|
||||
</Progress>
|
||||
</Button>
|
||||
<Progress
|
||||
percentage={
|
||||
state.progress?.percentageCompleted ??
|
||||
(state.details as any)?.buildProgressPercentage
|
||||
}
|
||||
>
|
||||
<StopIcon />
|
||||
</Progress>
|
||||
</Button>
|
||||
</WithTooltip>
|
||||
) : (
|
||||
<Button
|
||||
aria-label={`Start ${state.name}`}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
onClick={() => api.runTestProvider(state.id)}
|
||||
disabled={state.crashed || state.running}
|
||||
<WithTooltip
|
||||
hasChrome={false}
|
||||
trigger="hover"
|
||||
tooltip={<TooltipNote note={`Start ${state.name}`} />}
|
||||
>
|
||||
<PlayHollowIcon />
|
||||
</Button>
|
||||
<Button
|
||||
aria-label={`Start ${state.name}`}
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
onClick={() => api.runTestProvider(state.id)}
|
||||
disabled={state.crashed || state.running}
|
||||
>
|
||||
<PlayHollowIcon />
|
||||
</Button>
|
||||
</WithTooltip>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import React, { type FC, Fragment, useEffect, useState } from 'react';
|
||||
import React, { type FC, useEffect, useState } from 'react';
|
||||
|
||||
import { Addon_TypesEnum } from '@storybook/core/types';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { expect, fn, waitFor, within } from '@storybook/test';
|
||||
import { expect, fireEvent, fn, waitFor, within } from '@storybook/test';
|
||||
|
||||
import { type API, ManagerContext } from '@storybook/core/manager-api';
|
||||
import { userEvent } from '@storybook/testing-library';
|
||||
|
||||
import { SidebarBottomBase } from './SidebarBottom';
|
||||
|
||||
@ -156,18 +155,18 @@ export const DynamicHeight: StoryObj = {
|
||||
const screen = await within(canvasElement);
|
||||
|
||||
const toggleButton = await screen.getByLabelText(/Expand/);
|
||||
await userEvent.click(toggleButton);
|
||||
await fireEvent.click(toggleButton);
|
||||
|
||||
const content = await screen.findByText('CUSTOM CONTENT WITH DYNAMIC HEIGHT');
|
||||
const collapse = await screen.getByTestId('collapse');
|
||||
|
||||
await expect(content).toBeVisible();
|
||||
|
||||
await userEvent.click(toggleButton);
|
||||
await fireEvent.click(toggleButton);
|
||||
|
||||
await waitFor(() => expect(collapse.getBoundingClientRect()).toHaveProperty('height', 0));
|
||||
|
||||
await userEvent.click(toggleButton);
|
||||
await fireEvent.click(toggleButton);
|
||||
|
||||
await waitFor(() => expect(collapse.getBoundingClientRect()).not.toHaveProperty('height', 0));
|
||||
},
|
||||
|
@ -56,12 +56,14 @@ const Content = styled.div(({ theme }) => ({
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
padding: 12,
|
||||
padding: '12px 0',
|
||||
margin: '0 12px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 12,
|
||||
color: theme.color.defaultText,
|
||||
fontSize: theme.typography.size.s1,
|
||||
overflow: 'hidden',
|
||||
|
||||
'&:empty': {
|
||||
display: 'none',
|
||||
|
@ -274,21 +274,31 @@ export const TestingModule = ({
|
||||
)}
|
||||
<Filters>
|
||||
{hasTestProviders && (
|
||||
<CollapseToggle
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
onClick={toggleCollapsed}
|
||||
id="testing-module-collapse-toggle"
|
||||
aria-label={isCollapsed ? 'Expand testing module' : 'Collapse testing module'}
|
||||
<WithTooltip
|
||||
hasChrome={false}
|
||||
tooltip={
|
||||
<TooltipNote
|
||||
note={isCollapsed ? 'Expand testing module' : 'Collapse testing module'}
|
||||
/>
|
||||
}
|
||||
trigger="hover"
|
||||
>
|
||||
<ChevronSmallUpIcon
|
||||
style={{
|
||||
transform: isCollapsed ? 'none' : 'rotate(180deg)',
|
||||
transition: 'transform 250ms',
|
||||
willChange: 'auto',
|
||||
}}
|
||||
/>
|
||||
</CollapseToggle>
|
||||
<CollapseToggle
|
||||
variant="ghost"
|
||||
padding="small"
|
||||
onClick={toggleCollapsed}
|
||||
id="testing-module-collapse-toggle"
|
||||
aria-label={isCollapsed ? 'Expand testing module' : 'Collapse testing module'}
|
||||
>
|
||||
<ChevronSmallUpIcon
|
||||
style={{
|
||||
transform: isCollapsed ? 'none' : 'rotate(180deg)',
|
||||
transition: 'transform 250ms',
|
||||
willChange: 'auto',
|
||||
}}
|
||||
/>
|
||||
</CollapseToggle>
|
||||
</WithTooltip>
|
||||
)}
|
||||
|
||||
{errorCount > 0 && (
|
||||
|
@ -16,7 +16,7 @@ const createPanelActions = memoize(1)((api) => ({
|
||||
togglePosition: () => api.togglePanelPosition(),
|
||||
}));
|
||||
|
||||
const getPanels = (api: API) => {
|
||||
const getPanels = memoize(1)((api: API) => {
|
||||
const allPanels = api.getElements(Addon_TypesEnum.PANEL);
|
||||
const story = api.getCurrentStoryData();
|
||||
|
||||
@ -42,7 +42,7 @@ const getPanels = (api: API) => {
|
||||
});
|
||||
|
||||
return filteredPanels;
|
||||
};
|
||||
});
|
||||
|
||||
const mapper = ({ state, api }: Combo) => ({
|
||||
panels: getPanels(api),
|
||||
|
@ -195,7 +195,6 @@ export interface BuilderOptions {
|
||||
ignorePreview?: boolean;
|
||||
cache?: FileSystemCache;
|
||||
configDir: string;
|
||||
projectRoot?: string;
|
||||
docsMode?: boolean;
|
||||
features?: StorybookConfigRaw['features'];
|
||||
versionCheck?: VersionCheck;
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/builder-manager",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook manager builder",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/channels",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/client-logger",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/components",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Core Storybook Components",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/core-common",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook framework-agnostic API",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/core-events",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Event names used in storybook core",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/core-server",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook framework-agnostic API",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/csf-tools",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Parse and manipulate CSF and Storybook config files",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/docs-tools",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Shared utility functions for frameworks to implement docs",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/manager-api",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Core Storybook Manager API & Context",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/manager",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Core Storybook UI",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/node-logger",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/preview-api",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/preview",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/router",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Core Storybook Router",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/telemetry",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Telemetry logging for crash reports and usage statistics",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/theming",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Core Storybook Components",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/types",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Core Storybook TS Types",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/angular",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.",
|
||||
"keywords": [
|
||||
"storybook",
|
||||
@ -44,7 +44,6 @@
|
||||
"@storybook/manager-api": "workspace:*",
|
||||
"@storybook/preview-api": "workspace:*",
|
||||
"@storybook/theming": "workspace:*",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/react": "^18.0.37",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/semver": "^7.3.4",
|
||||
@ -73,6 +72,7 @@
|
||||
"@angular/platform-browser": "^17.3.0",
|
||||
"@angular/platform-browser-dynamic": "^17.3.0",
|
||||
"@types/cross-spawn": "^6.0.2",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/tmp": "^0.2.3",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"tmp": "^0.2.1",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/ember",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.",
|
||||
"homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember",
|
||||
"bugs": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/experimental-nextjs-vite",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for Next.js and Vite",
|
||||
"keywords": [
|
||||
"storybook",
|
||||
@ -103,7 +103,7 @@
|
||||
"vite-plugin-storybook-nextjs": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/node": "^22.0.0",
|
||||
"next": "^15.0.3",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/html-vite",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for HTML and Vite: Develop HTML in isolation with Hot Reloading.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/html-webpack5",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -50,10 +50,10 @@
|
||||
"@storybook/builder-webpack5": "workspace:*",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/html": "workspace:*",
|
||||
"@storybook/preset-html-webpack": "workspace:*",
|
||||
"@types/node": "^22.0.0"
|
||||
"@storybook/preset-html-webpack": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/nextjs",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for Next.js",
|
||||
"keywords": [
|
||||
"storybook",
|
||||
@ -148,7 +148,6 @@
|
||||
"@storybook/preset-react-webpack": "workspace:*",
|
||||
"@storybook/react": "workspace:*",
|
||||
"@storybook/test": "workspace:*",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/semver": "^7.3.4",
|
||||
"babel-loader": "^9.1.3",
|
||||
"css-loader": "^6.7.3",
|
||||
@ -175,6 +174,7 @@
|
||||
"@types/babel__plugin-transform-runtime": "^7",
|
||||
"@types/babel__preset-env": "^7",
|
||||
"@types/loader-utils": "^2.0.5",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/react-refresh": "^0",
|
||||
"next": "^15.0.3",
|
||||
"typescript": "^5.3.2",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/preact-vite",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for Preact and Vite: Develop Preact components in isolation with Hot Reloading.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/preact-webpack5",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for Preact: Develop Preact Component in isolation.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -49,10 +49,10 @@
|
||||
"dependencies": {
|
||||
"@storybook/builder-webpack5": "workspace:*",
|
||||
"@storybook/preact": "workspace:*",
|
||||
"@storybook/preset-preact-webpack": "workspace:*",
|
||||
"@types/node": "^22.0.0"
|
||||
"@storybook/preset-preact-webpack": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"preact": "^10.5.13",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/react-native-web-vite",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Develop react-native components an isolated web environment with hot reloading.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -53,12 +53,15 @@
|
||||
"prep": "jiti ../../../scripts/prepare/bundle.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.26.3",
|
||||
"@babel/preset-react": "^7.26.3",
|
||||
"@bunchtogether/vite-plugin-flow": "^1.0.2",
|
||||
"@joshwooding/vite-plugin-react-docgen-typescript": "0.4.2",
|
||||
"@storybook/builder-vite": "workspace:*",
|
||||
"@storybook/react": "workspace:*",
|
||||
"@storybook/react-vite": "workspace:*",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"vite-plugin-babel": "^1.3.0",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -3,6 +3,7 @@ import { viteFinal as reactViteFinal } from '@storybook/react-vite/preset';
|
||||
import { esbuildFlowPlugin, flowPlugin } from '@bunchtogether/vite-plugin-flow';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import type { InlineConfig, PluginOption } from 'vite';
|
||||
import babel from 'vite-plugin-babel';
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
import type { FrameworkOptions, StorybookConfig } from './types';
|
||||
@ -64,10 +65,12 @@ export function reactNativeWeb(): PluginOption {
|
||||
export const viteFinal: StorybookConfig['viteFinal'] = async (config, options) => {
|
||||
const { mergeConfig } = await import('vite');
|
||||
|
||||
const { pluginReactOptions = {} } =
|
||||
const { pluginReactOptions = {}, pluginBabelOptions = {} } =
|
||||
await options.presets.apply<FrameworkOptions>('frameworkOptions');
|
||||
|
||||
const { plugins = [], ...reactConfigWithoutPlugins } = await reactViteFinal(config, options);
|
||||
const isDevelopment = options.configType !== 'PRODUCTION';
|
||||
|
||||
const reactConfig = await reactViteFinal(config, options);
|
||||
|
||||
return mergeConfig(reactConfigWithoutPlugins, {
|
||||
plugins: [
|
||||
@ -88,6 +91,7 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, options) =
|
||||
],
|
||||
optimizeDeps: {
|
||||
esbuildOptions: {
|
||||
// fix for react native packages shipping with flow types untranspiled
|
||||
plugins: [esbuildFlowPlugin(new RegExp(/\.(flow|jsx?)$/), (_path: string) => 'jsx')],
|
||||
},
|
||||
},
|
||||
|
@ -6,9 +6,17 @@ import type {
|
||||
} from '@storybook/react-vite';
|
||||
|
||||
import type { BabelOptions, Options as ReactOptions } from '@vitejs/plugin-react';
|
||||
import type { BabelPluginOptions } from 'vite-plugin-babel';
|
||||
|
||||
export type FrameworkOptions = FrameworkOptionsBase & {
|
||||
pluginReactOptions?: Omit<ReactOptions, 'babel'> & { babel?: BabelOptions };
|
||||
pluginBabelOptions?: BabelPluginOptions & {
|
||||
presetReact?: {
|
||||
[key: string]: any;
|
||||
runtime?: 'automatic' | 'classic';
|
||||
importSource?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
type FrameworkName = CompatibleString<'@storybook/react-native-web-vite'>;
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/react-vite",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for React and Vite: Develop React components in isolation with Hot Reloading.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/react-webpack5",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for React: Develop React Component in isolation with Hot Reloading.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -49,7 +49,9 @@
|
||||
"dependencies": {
|
||||
"@storybook/builder-webpack5": "workspace:*",
|
||||
"@storybook/preset-react-webpack": "workspace:*",
|
||||
"@storybook/react": "workspace:*",
|
||||
"@storybook/react": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/server-webpack5",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -49,10 +49,10 @@
|
||||
"dependencies": {
|
||||
"@storybook/builder-webpack5": "workspace:*",
|
||||
"@storybook/preset-server-webpack": "workspace:*",
|
||||
"@storybook/server": "workspace:*",
|
||||
"@types/node": "^22.0.0"
|
||||
"@storybook/server": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/svelte-vite",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for Svelte and Vite: Develop Svelte components in isolation with Hot Reloading.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/svelte-webpack5",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/sveltekit",
|
||||
"version": "8.5.0-beta.4",
|
||||
"version": "8.5.0-beta.7",
|
||||
"description": "Storybook for SvelteKit",
|
||||
"keywords": [
|
||||
"storybook",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user