Skip to content

Commit

Permalink
Merge pull request #28463 from storybookjs/version-non-patch-from-8.2…
Browse files Browse the repository at this point in the history
….0-beta.0

Release: Prerelease 8.2.0-beta.1
  • Loading branch information
valentinpalkovic authored Jul 8, 2024
2 parents 78c3f60 + afb0dd1 commit f1e43d2
Show file tree
Hide file tree
Showing 21 changed files with 843 additions and 767 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 8.2.0-beta.1

- Babel: Ensure story files not transpiled earlier than ES2017 - [#28469](https://github.com/storybookjs/storybook/pull/28469), thanks @kasperpeulen!
- Blocks: Prebundle `tocbot` - [#28318](https://github.com/storybookjs/storybook/pull/28318), thanks @shilman!
- Core: Make sure StorybookError message shows up in browser console and interactions panel - [#28464](https://github.com/storybookjs/storybook/pull/28464), thanks @kasperpeulen!
- Index: Fix MDX to override project-level autodocs - [#28461](https://github.com/storybookjs/storybook/pull/28461), thanks @shilman!
- Test: Improve MountMustBeDestructuredError error message - [#28468](https://github.com/storybookjs/storybook/pull/28468), thanks @kasperpeulen!

## 8.2.0-beta.0

- Addon Interactions: Use unique keys when rendering array nodes in panel - [#28423](https://github.com/storybookjs/storybook/pull/28423), thanks @yannbf!
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ You will need to have the following installed:
- git
- node
- yarn
- (bun)[https://bun.sh/]
- [bun](https://bun.sh/)

## Using fnm as a Node version manager

Expand Down
2 changes: 1 addition & 1 deletion code/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ module.exports = {
},
},
{
files: ['**/core-events/src/**/*'],
files: ['./core/src/preview-errors.ts'],
excludedFiles: ['**/*.test.*'],
rules: {
'local-rules/no-duplicated-error-codes': 'error',
Expand Down
44 changes: 23 additions & 21 deletions code/core/src/ERRORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ Second use the `StorybookError` class to define custom errors with specific code
```typescript
import { StorybookError } from './storybook-error';
export class YourCustomError extends StorybookError {
readonly category: Category; // The category to which the error belongs. Check the source in client-errors.ts or server-errors.ts for reference.
readonly code: number; // The numeric code for the error.

template(): string {
// A function that returns the error message.
constructor() {
super({
// The category to which the error belongs. Check the source in client-errors.ts or server-errors.ts for reference.
category: Category,
// The numeric code for the error.
code: number,
// The error message.
message: string,
});
}
}
```
Expand All @@ -42,7 +46,7 @@ export class YourCustomError extends StorybookError {
| ------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| category | `Category` | The category to which the error belongs. |
| code | `number` | The numeric code for the error. |
| template | `() => string` | Function that returns a properly written error message. |
| message | `string` | The error message. |
| data | `Object` | Optional. Data associated with the error. Used to provide additional information in the error message or to be passed to telemetry. |
| documentation | `boolean` or `string` | Optional. Should be set to `true` **if the error is documented on the Storybook website**. If defined as string, it should be a custom documentation link. |

Expand All @@ -51,28 +55,26 @@ export class YourCustomError extends StorybookError {
```typescript
// Define a custom error with a numeric code and a static error message template.
export class StorybookIndexGenerationError extends StorybookError {
category = Category.Generic;
code = 1;

template(): string {
return `Storybook failed when generating an index for your stories. Check the stories field in your main.js`;
constructor() {
super({
category: Category.Generic,
code: 1,
message: `Storybook failed when generating an index for your stories. Check the stories field in your main.js`,
});
}
}

// Define a custom error with a numeric code and a dynamic error message template based on properties from the constructor.
// Define a custom error with a numeric code and a dynamic error message based on properties from the constructor.
export class InvalidFileExtensionError extends StorybookError {
category = Category.Validation;
code = 2;
documentation = 'https://some-custom-documentation.com/validation-errors';

// extra properties are defined in the constructor via a data property, which is available in any class method
// always use this data Object notation!
constructor(public data: { extension: string }) {
super();
}

template(): string {
return `Invalid file extension found: ${this.data.extension}.`;
super({
category: Category.Validation,
code: 2,
documentation: 'https://some-custom-documentation.com/validation-errors',
message: `Invalid file extension found: ${data.extension}.`,
});
}
}

Expand Down
1 change: 0 additions & 1 deletion code/core/src/__tests/preview-errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ describe('UnknownFlowArgTypesError', () => {
const typeError = new UnknownArgTypesError({ type, language: 'Typescript' });
expect(typeError.message).toMatchInlineSnapshot(`
"There was a failure when generating detailed ArgTypes in Typescript for:
{
"name": "signature",
"raw": "SomeType['someProperty']"
Expand Down
24 changes: 11 additions & 13 deletions code/core/src/__tests/storybook-error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { StorybookError } from '../storybook-error';

describe('StorybookError', () => {
class TestError extends StorybookError {
category = 'TEST_CATEGORY';

code = 123;

template() {
return 'This is a test error.';
constructor(documentation?: StorybookError['documentation']) {
super({
category: 'TEST_CATEGORY',
code: 123,
message: 'This is a test error.',
documentation,
});
}
}

Expand All @@ -24,16 +25,14 @@ describe('StorybookError', () => {
});

it('should generate the correct message with internal documentation link', () => {
const error = new TestError();
error.documentation = true;
const error = new TestError(true);
const expectedMessage =
'This is a test error.\n\nMore info: https://storybook.js.org/error/SB_TEST_CATEGORY_0123\n';
expect(error.message).toBe(expectedMessage);
});

it('should generate the correct message with external documentation link', () => {
const error = new TestError();
error.documentation = 'https://example.com/docs/test-error';
const error = new TestError('https://example.com/docs/test-error');
expect(error.message).toMatchInlineSnapshot(`
"This is a test error.
Expand All @@ -43,11 +42,10 @@ describe('StorybookError', () => {
});

it('should generate the correct message with multiple external documentation links', () => {
const error = new TestError();
error.documentation = [
const error = new TestError([
'https://example.com/docs/first-error',
'https://example.com/docs/second-error',
];
]);
expect(error.message).toMatchInlineSnapshot(`
"This is a test error.
Expand Down
32 changes: 30 additions & 2 deletions code/core/src/core-server/presets/common-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,36 @@ export const favicon = async (

export const babel = async (_: unknown, options: Options) => {
const { presets } = options;

return presets.apply('babelDefault', {}, options);
const babelDefault = ((await presets.apply('babelDefault', {}, options)) ?? {}) as Record<
string,
any
>;
return {
...babelDefault,
// This override makes sure that we will never transpile babel further down then the browsers that storybook supports.
// This is needed to support the mount property of the context described here:
// https://storybook.js.org/docs/writing-tests/interaction-testing#run-code-before-each-test
overrides: [
...(babelDefault?.overrides ?? []),
{
include: /\.(story|stories)\.[cm]?[jt]sx?$/,
presets: [
[
'@babel/preset-env',
{
bugfixes: true,
targets: {
// This is the same browser supports that we use to bundle our manager and preview code.
chrome: 100,
safari: 15,
firefox: 91,
},
},
],
],
},
],
};
};

export const title = (previous: string, options: Options) =>
Expand Down
115 changes: 112 additions & 3 deletions code/core/src/core-server/utils/StoryIndexGenerator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,43 @@ describe('StoryIndexGenerator', () => {
`);
});

it('adds the autodocs tag to the autogenerated docs entries', async () => {
it('generates an entry for every CSF file when projectTags contains autodocs', async () => {
const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(
'./src/**/*.stories.(ts|js|mjs|jsx)',
options
);

const generator = new StoryIndexGenerator([specifier], autodocsOptions);
generator.getProjectTags = () => ['dev', 'test', 'autodocs'];
await generator.initialize();

expect(Object.keys((await generator.getIndex()).entries)).toMatchInlineSnapshot(`
[
"a--docs",
"a--story-one",
"b--docs",
"b--story-one",
"d--docs",
"d--story-one",
"h--docs",
"h--story-one",
"componentpath-extension--docs",
"componentpath-extension--story-one",
"componentpath-noextension--docs",
"componentpath-noextension--story-one",
"componentpath-package--docs",
"componentpath-package--story-one",
"first-nested-deeply-f--docs",
"first-nested-deeply-f--story-one",
"nested-button--docs",
"nested-button--story-one",
"second-nested-g--docs",
"second-nested-g--story-one",
]
`);
});

it('adds the autodocs tag to the autogenerated docs entries when docsOptions.autodocs = true', async () => {
const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(
'./src/**/*.stories.(ts|js|mjs|jsx)',
options
Expand All @@ -626,6 +662,22 @@ describe('StoryIndexGenerator', () => {
);
});

it('adds the autodocs tag to the autogenerated docs entries when projectTags contains autodocs', async () => {
const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(
'./src/**/*.stories.(ts|js|mjs|jsx)',
options
);

const generator = new StoryIndexGenerator([specifier], autodocsOptions);
generator.getProjectTags = () => ['dev', 'test', 'autodocs'];
await generator.initialize();

const index = await generator.getIndex();
expect(index.entries['first-nested-deeply-f--docs'].tags).toEqual(
expect.arrayContaining(['autodocs'])
);
});

it('throws an error if you attach a named MetaOf entry which clashes with a tagged autodocs entry', async () => {
const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(
'./src/B.stories.ts',
Expand Down Expand Up @@ -793,7 +845,7 @@ describe('StoryIndexGenerator', () => {
`);
});

it('allows you to override autodocs with MetaOf if it is automatic', async () => {
it('allows you to override autodocs with MetaOf when docsOptions.autodocs = true', async () => {
const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(
'./src/A.stories.js',
options
Expand Down Expand Up @@ -852,6 +904,63 @@ describe('StoryIndexGenerator', () => {
`);
});

it('allows you to override autodocs with MetaOf when projectTags contains autodocs', async () => {
const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(
'./src/A.stories.js',
options
);

const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(
'./errors/A.mdx',
options
);

const generator = new StoryIndexGenerator([csfSpecifier, docsSpecifier], autodocsOptions);
generator.getProjectTags = () => ['dev', 'test', 'autodocs'];
await generator.initialize();

expect(await generator.getIndex()).toMatchInlineSnapshot(`
{
"entries": {
"a--docs": {
"id": "a--docs",
"importPath": "./errors/A.mdx",
"name": "docs",
"storiesImports": [
"./src/A.stories.js",
],
"tags": [
"dev",
"test",
"autodocs",
"component-tag",
"story-tag",
"attached-mdx",
],
"title": "A",
"type": "docs",
},
"a--story-one": {
"componentPath": undefined,
"id": "a--story-one",
"importPath": "./src/A.stories.js",
"name": "Story One",
"tags": [
"dev",
"test",
"autodocs",
"component-tag",
"story-tag",
],
"title": "A",
"type": "story",
},
},
"v": 5,
}
`);
});

it('generates a combined entry if there are two stories files for the same title', async () => {
const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(
'./duplicate/*.stories.(ts|js|mjs|jsx)',
Expand Down Expand Up @@ -1418,7 +1527,7 @@ describe('StoryIndexGenerator', () => {
type: 'story',
};
expect(() => {
generator.chooseDuplicate(mockEntry, { ...mockEntry, importPath: 'DifferentPath' });
generator.chooseDuplicate(mockEntry, { ...mockEntry, importPath: 'DifferentPath' }, []);
}).toThrowErrorMatchingInlineSnapshot(`[Error: Duplicate stories with id: StoryId]`);
});

Expand Down
13 changes: 8 additions & 5 deletions code/core/src/core-server/utils/StoryIndexGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ export class StoryIndexGenerator {
}
}

chooseDuplicate(firstEntry: IndexEntry, secondEntry: IndexEntry): IndexEntry {
chooseDuplicate(firstEntry: IndexEntry, secondEntry: IndexEntry, projectTags: Tag[]): IndexEntry {
// NOTE: it is possible for the same entry to show up twice (if it matches >1 glob). That's OK.
if (firstEntry.importPath === secondEntry.importPath) {
return firstEntry;
Expand Down Expand Up @@ -555,13 +555,16 @@ export class StoryIndexGenerator {
}

// If you link a file to a tagged CSF file, you have probably made a mistake
if (worseEntry.tags?.includes(AUTODOCS_TAG) && this.options.docs.autodocs !== true)
if (
worseEntry.tags?.includes(AUTODOCS_TAG) &&
!(this.options.docs.autodocs === true || projectTags?.includes(AUTODOCS_TAG))
)
throw new IndexingError(
`You created a component docs page for '${worseEntry.title}', but also tagged the CSF file with '${AUTODOCS_TAG}'. This is probably a mistake.`,
[betterEntry.importPath, worseEntry.importPath]
);

// Otherwise the existing entry is created by `autodocs=true` which allowed to be overridden.
// Otherwise the existing entry is created by project-level autodocs which is allowed to be overridden.
} else {
// If both entries are templates (e.g. you have two CSF files with the same title), then
// we need to merge the entries. We'll use the first one's name and importPath,
Expand Down Expand Up @@ -617,7 +620,7 @@ export class StoryIndexGenerator {
try {
const existing = indexEntries[entry.id];
if (existing) {
indexEntries[entry.id] = this.chooseDuplicate(existing, entry);
indexEntries[entry.id] = this.chooseDuplicate(existing, entry, projectTags);
} else {
indexEntries[entry.id] = entry;
}
Expand Down Expand Up @@ -709,7 +712,7 @@ export class StoryIndexGenerator {
}

getProjectTags(previewCode?: string) {
let projectTags = [];
let projectTags = [] as Tag[];
const defaultTags = ['dev', 'test'];
const extraTags = this.options.docs.autodocs === true ? [AUTODOCS_TAG] : [];
if (previewCode) {
Expand Down
Loading

0 comments on commit f1e43d2

Please sign in to comment.