Skip to content

Commit

Permalink
Merge branch 'next' into 24351-bug-error-when-switching-themes-addon-…
Browse files Browse the repository at this point in the history
…themes
  • Loading branch information
JReinhold authored Oct 27, 2023
2 parents 8102813 + 38d7bca commit 2245d79
Show file tree
Hide file tree
Showing 49 changed files with 1,152 additions and 134 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ test-results
!/**/.yarn/plugins
!/**/.yarn/sdks
!/**/.yarn/versions
!/**/.yarn/patches
/**/.pnp.*
!/node_modules

Expand Down
37 changes: 37 additions & 0 deletions code/.yarn/patches/@vitest-expect-npm-0.34.5-8031508efe.patch

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion code/addons/a11y/src/a11yRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,18 @@ const run = async (storyId: string) => {
}

const result = await axe.run(htmlElement, options);

// Axe result contains class instances, which telejson deserializes in a
// way that violates:
// Content Security Policy directive: "script-src 'self' 'unsafe-inline'".
const resultJson = JSON.parse(JSON.stringify(result));

// It's possible that we requested a new run on a different story.
// Unfortunately, axe doesn't support a cancel method to abort current run.
// We check if the story we run against is still the current one,
// if not, trigger a new run using the current story
if (activeStoryId === storyId) {
channel.emit(EVENTS.RESULT, result);
channel.emit(EVENTS.RESULT, resultJson);
} else {
active = false;
run(activeStoryId);
Expand Down
7 changes: 6 additions & 1 deletion code/addons/actions/src/addArgs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import type { ArgsEnhancer } from '@storybook/types';
import { addActionsFromArgTypes, inferActionsFromArgTypesRegex } from './addArgsHelpers';
import {
addActionsFromArgTypes,
attachActionsToFunctionMocks,
inferActionsFromArgTypesRegex,
} from './addArgsHelpers';

export const argsEnhancers: ArgsEnhancer[] = [
addActionsFromArgTypes,
inferActionsFromArgTypesRegex,
attachActionsToFunctionMocks,
];
33 changes: 32 additions & 1 deletion code/addons/actions/src/addArgsHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-underscore-dangle,no-param-reassign */
import type { Args, Renderer, ArgsEnhancer } from '@storybook/types';
import { action } from './runtime/action';

Expand Down Expand Up @@ -31,7 +32,7 @@ export const inferActionsFromArgTypesRegex: ArgsEnhancer<Renderer> = (context) =

return argTypesMatchingRegex.reduce((acc, [name, argType]) => {
if (isInInitialArgs(name, initialArgs)) {
acc[name] = action(name);
acc[name] = action(name, { implicit: true });
}
return acc;
}, {} as Args);
Expand Down Expand Up @@ -61,3 +62,33 @@ export const addActionsFromArgTypes: ArgsEnhancer<Renderer> = (context) => {
return acc;
}, {} as Args);
};

export const attachActionsToFunctionMocks: ArgsEnhancer<Renderer> = (context) => {
const {
initialArgs,
argTypes,
parameters: { actions },
} = context;
if (actions?.disable || !argTypes) {
return {};
}

const argTypesWithAction = Object.entries(initialArgs).filter(
([, value]) =>
typeof value === 'function' &&
'_isMockFunction' in value &&
value._isMockFunction &&
!value._actionAttached
);

return argTypesWithAction.reduce((acc, [key, value]) => {
const previous = value.getMockImplementation();
value.mockImplementation((...args: unknown[]) => {
action(key)(...args);
return previous?.(...args);
});
// this enhancer is being called multiple times
value._actionAttached = true;
return acc;
}, {} as Args);
};
1 change: 1 addition & 0 deletions code/addons/actions/src/models/ActionOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ interface Options {
depth: number; // backards compatibility, remove in 7.0
clearOnStoryChange: boolean;
limit: number;
implicit: boolean;
}

export type ActionOptions = Partial<Options> & Partial<TelejsonOptions>;
17 changes: 17 additions & 0 deletions code/addons/actions/src/runtime/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ export function action(name: string, options: ActionOptions = {}): HandlerFuncti
};

const handler = function actionHandler(...args: any[]) {
// TODO: Enable once codemods are finished
// if (options.implicit) {
// const preview =
// '__STORYBOOK_PREVIEW__' in global
// ? (global.__STORYBOOK_PREVIEW__ as PreviewWeb<Renderer>)
// : undefined;
// if (
// preview?.storyRenders.some(
// (render) => render.phase === 'playing' || render.phase === 'rendering'
// )
// ) {
// console.warn(
// 'Can not use implicit actions during rendering or playing of a story.'
// );
// }
// }

const channel = addons.getChannel();
// this makes sure that in js enviroments like react native you can still get an id
const id = generateId();
Expand Down
25 changes: 24 additions & 1 deletion code/addons/interactions/src/components/Interaction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { type Call, CallStates, type ControlStates } from '@storybook/instrument
import { styled, typography } from '@storybook/theming';
import { transparentize } from 'polished';

import { MatcherResult } from './MatcherResult';
import { Expected, MatcherResult, Received } from './MatcherResult';
import { MethodCall } from './MethodCall';
import { StatusIcon } from './StatusIcon';

Expand Down Expand Up @@ -120,6 +120,29 @@ const Exception = ({ exception }: { exception: Call['exception'] }) => {
return (
<RowMessage>
<pre>{paragraphs[0]}</pre>

{exception.showDiff && exception.diff ? (
<>
<br />
<MatcherResult message={exception.diff} style={{ padding: 0 }} />
</>
) : (
<pre>
<br />
{exception.expected && (
<>
Expected: <Expected value={exception.expected} />
<br />
</>
)}
{exception.actual && (
<>
Received: <Received value={exception.actual} />
<br />
</>
)}
</pre>
)}
{more && <p>See the full stack trace in the browser console.</p>}
</RowMessage>
);
Expand Down
9 changes: 8 additions & 1 deletion code/addons/interactions/src/components/MatcherResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,21 @@ export const Expected = ({ value, parsed }: { value: any; parsed?: boolean }) =>
return <StyledExpected>{value}</StyledExpected>;
};

export const MatcherResult = ({ message }: { message: string }) => {
export const MatcherResult = ({
message,
style = {},
}: {
message: string;
style?: React.CSSProperties;
}) => {
const lines = message.split('\n');
return (
<pre
style={{
margin: 0,
padding: '8px 10px 8px 36px',
fontSize: typography.size.s1,
...style,
}}
>
{lines.flatMap((line: string, index: number) => {
Expand Down
25 changes: 22 additions & 3 deletions code/addons/interactions/src/preview.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-param-reassign,no-underscore-dangle */
/// <reference types="node" />

import { addons } from '@storybook/preview-api';
Expand All @@ -9,6 +10,7 @@ import type {
PlayFunction,
PlayFunctionContext,
StepLabel,
Args,
} from '@storybook/types';
import { instrument } from '@storybook/instrumenter';
import { ModuleMocker } from 'jest-mock';
Expand All @@ -30,14 +32,13 @@ const addSpies = (id: string, val: any, key?: string): any => {
try {
if (Object.prototype.toString.call(val) === '[object Object]') {
// We have to mutate the original object for this to survive HMR.
// eslint-disable-next-line no-restricted-syntax, no-param-reassign
// eslint-disable-next-line no-restricted-syntax
for (const [k, v] of Object.entries(val)) val[k] = addSpies(id, v, k);
return val;
}
if (Array.isArray(val)) {
return val.map((item, index) => addSpies(id, item, `${key}[${index}]`));
}
// eslint-disable-next-line no-underscore-dangle
if (typeof val === 'function' && val.isAction && !val._isMockFunction) {
Object.defineProperty(val, 'name', { value: key, writable: false });
Object.defineProperty(val, '__storyId__', { value: id, writable: false });
Expand All @@ -54,7 +55,25 @@ const addSpies = (id: string, val: any, key?: string): any => {
const addActionsFromArgTypes: ArgsEnhancer<Renderer> = ({ id, initialArgs }) =>
addSpies(id, initialArgs);

export const argsEnhancers = [addActionsFromArgTypes];
const instrumentSpies: ArgsEnhancer = ({ initialArgs }) => {
const argTypesWithAction = Object.entries(initialArgs).filter(
([, value]) =>
typeof value === 'function' &&
'_isMockFunction' in value &&
value._isMockFunction &&
!value._instrumented
);

return argTypesWithAction.reduce((acc, [key, value]) => {
const instrumented = instrument({ [key]: () => value }, { retain: true })[key];
acc[key] = instrumented();
// this enhancer is being called multiple times
value._instrumented = true;
return acc;
}, {} as Args);
};

export const argsEnhancers = [addActionsFromArgTypes, instrumentSpies];

export const { step: runStep } = instrument(
{
Expand Down
5 changes: 0 additions & 5 deletions code/builders/builder-vite/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Build your stories with [vite](https://vitejs.dev/) for fast startup times and n
- [Getting started with Vite and Storybook (on a new project)](#getting-started-with-vite-and-storybook-on-a-new-project)
- [Migration from webpack / CRA](#migration-from-webpack--cra)
- [Customize Vite config](#customize-vite-config)
- [Svelte Options](#svelte-options)
- [TypeScript](#typescript)
- [React Docgen](#react-docgen)
- [Note about working directory](#note-about-working-directory)
Expand Down Expand Up @@ -113,10 +112,6 @@ The `configType` variable will be either `"DEVELOPMENT"` or `"PRODUCTION"`.

The function should return the updated Vite configuration.

### Svelte Options

When using this builder with Svelte, your `svelte.config.js` file will be used automatically.

### TypeScript

Configure your `.storybook/main.ts` to use TypeScript:
Expand Down
6 changes: 3 additions & 3 deletions code/frameworks/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,13 @@
"@types/babel__core": "^7",
"@types/babel__plugin-transform-runtime": "^7",
"@types/babel__preset-env": "^7",
"next": "13.5.4",
"next": "^14.0.0",
"typescript": "^4.9.3",
"webpack": "^5.65.0"
},
"peerDependencies": {
"@next/font": "^13.0.0",
"next": "^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0",
"@next/font": "^13.0.0|| ^14.0.0",
"next": "^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
"webpack": "^5.0.0"
Expand Down
2 changes: 1 addition & 1 deletion code/frameworks/nextjs/src/images/webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const configureImageDefaults = (baseConfig: WebpackConfig): void => {
'next/image': path.resolve(__dirname, './images/next-image'),
};

if (semver.satisfies(version, '^13.0.0')) {
if (semver.satisfies(version, '>=13.0.0')) {
resolve.alias = {
...resolve.alias,
'sb-original/next/legacy/image': require.resolve('next/legacy/image'),
Expand Down
12 changes: 2 additions & 10 deletions code/frameworks/nextjs/src/nextImport/webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,11 @@ export function configureNextImport(baseConfig: WebpackConfig) {
const nextJSVersion = getNextjsVersion();

const isNext12 = semver.satisfies(nextJSVersion, '~12');
const isNext13 = semver.satisfies(nextJSVersion, '~13');
const isNextVersionSmallerThan12dot2 = semver.lt(nextJSVersion, '12.2.0');
const isNextVersionSmallerThan13 = semver.lt(nextJSVersion, '13.0.0');

baseConfig.plugins = baseConfig.plugins ?? [];

if (!isNext13) {
baseConfig.plugins.push(
new IgnorePlugin({
resourceRegExp: /next\/legacy\/image$/,
})
);
}

if (!isNext12 || isNextVersionSmallerThan12dot2) {
baseConfig.plugins.push(
new IgnorePlugin({
Expand All @@ -32,7 +23,8 @@ export function configureNextImport(baseConfig: WebpackConfig) {
if (isNextVersionSmallerThan13) {
baseConfig.plugins.push(
new IgnorePlugin({
resourceRegExp: /next\/dist\/shared\/lib\/hooks-client-context$/,
// ignore next/dist/shared/lib/hooks-client-context and next/legacy/image imports
resourceRegExp: /(next\/dist\/shared\/lib\/hooks-client-context|next\/legacy\/image)$/,
})
);
}
Expand Down
3 changes: 3 additions & 0 deletions code/jest.config.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const modulesToTransform = [
'@angular',
'@lit',
'@mdx-js',
'@vitest',
'ccount',
'character-entities',
'decode-named-character-reference',
Expand Down Expand Up @@ -60,6 +61,8 @@ module.exports = {
path.resolve('./__mocks__/fileMock.js'),
'\\.(css|scss|stylesheet)$': path.resolve('./__mocks__/styleMock.js'),
'\\.(md)$': path.resolve('./__mocks__/htmlMock.js'),
'@vitest/utils/(.*)': '@vitest/utils/dist/$1.js',
'@vitest/utils': '@vitest/utils/dist/index.js',
},
transform: {
'^.+\\.(t|j)sx?$': ['@swc/jest', swcrc],
Expand Down
4 changes: 3 additions & 1 deletion code/lib/instrumenter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@
"@storybook/client-logger": "workspace:*",
"@storybook/core-events": "workspace:*",
"@storybook/global": "^5.0.0",
"@storybook/preview-api": "workspace:*"
"@storybook/preview-api": "workspace:*",
"@vitest/utils": "^0.34.6",
"util": "^0.12.4"
},
"devDependencies": {
"typescript": "~4.9.3"
Expand Down
Loading

0 comments on commit 2245d79

Please sign in to comment.