Skip to content

Commit 7f83123

Browse files
authored
Merge pull request #31543 from storybookjs/version-non-patch-from-9.0.0-rc.4
Release: Prerelease 9.0.0-rc.5
2 parents 0f1d97b + d5983f7 commit 7f83123

File tree

461 files changed

+5676
-6651
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

461 files changed

+5676
-6651
lines changed

.cursor/environment.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"snapshot": "snapshot-20250521-0222c8bd-0a11-48ab-a2a8-380203843e05",
3+
"install": "cd /workspace/scripts && yarn && cd ../code && yarn && yarn task --task=compile --start-from=compile",
4+
"start": "cd /workspace/code && yarn test",
5+
"terminals": []
6+
}

CHANGELOG.prerelease.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 9.0.0-rc.5
2+
3+
- Addon A11y: Improve selector automigration detection - [#31392](https://github.com/storybookjs/storybook/pull/31392), thanks @yannbf!
4+
- Addon Vitest: Support `vitest.projects.ts` file as workspace file during postinstall - [#31565](https://github.com/storybookjs/storybook/pull/31565), thanks @ghengeveld!
5+
- Addon-Vitest: Always clean coverage before (re)running - [#31540](https://github.com/storybookjs/storybook/pull/31540), thanks @JReinhold!
6+
- Automigration: Fix wrap require wrapper - [#31569](https://github.com/storybookjs/storybook/pull/31569), thanks @valentinpalkovic!
7+
- Controls: Remove empty state video link - [#31539](https://github.com/storybookjs/storybook/pull/31539), thanks @kylegach!
8+
- Presets: Use `.js` files when `.cjs` files are passed for entries that should be ESM - [#31556](https://github.com/storybookjs/storybook/pull/31556), thanks @JReinhold!
9+
- Pseudo States: Ignore escaped pseudo-class names - [#31515](https://github.com/storybookjs/storybook/pull/31515), thanks @sentience!
10+
111
## 9.0.0-rc.4
212

313
- Addon Vitest: Improve handling multiple browser mode projects - [#31508](https://github.com/storybookjs/storybook/pull/31508), thanks @yannbf!

code/addons/docs/src/blocks/components/ArgsTable/Empty.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react';
33

44
import { EmptyTabContent, Link } from 'storybook/internal/components';
55

6-
import { DocumentIcon, VideoIcon } from '@storybook/icons';
6+
import { DocumentIcon } from '@storybook/icons';
77

88
import { styled } from 'storybook/theming';
99

@@ -30,12 +30,6 @@ const Links = styled.div(({ theme }) => ({
3030
gap: 25,
3131
}));
3232

33-
const Divider = styled.div(({ theme }) => ({
34-
width: 1,
35-
height: 16,
36-
backgroundColor: theme.appBorderColor,
37-
}));
38-
3933
export const Empty: FC<EmptyProps> = ({ inAddonPanel }) => {
4034
const [isLoading, setIsLoading] = useState(true);
4135

@@ -72,10 +66,6 @@ export const Empty: FC<EmptyProps> = ({ inAddonPanel }) => {
7266
<Links>
7367
{inAddonPanel && (
7468
<>
75-
<Link href="https://youtu.be/0gOfS6K0x0E" target="_blank" withArrow>
76-
<VideoIcon /> Watch 5m video
77-
</Link>
78-
<Divider />
7969
<Link
8070
href="https://storybook.js.org/docs/essentials/controls"
8171
target="_blank"

code/addons/pseudo-states/src/constants.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@ export const PARAM_KEY = 'pseudo';
66
// E.g. ::-webkit-scrollbar-thumb.pseudo-hover is not a valid selector
77
export const EXCLUDED_PSEUDO_ELEMENT_PATTERNS = ['::-(webkit|moz|ms)-[a-z-]+', '::part\\([^)]+\\)'];
88

9+
/**
10+
* This lookbehind ensures we don't match escaped pseudo-states commonly used in Tailwind (e.g.
11+
* `.foo\:hover\:bar:hover`). We do this by skipping pseudo-states preceded by an odd number of `\`
12+
* escapes.
13+
*
14+
* @example
15+
*
16+
* Excluded:
17+
*
18+
* ```
19+
* .foo\:pseudo-selector {}
20+
* .foo\\\:pseudo-selector {}
21+
* ```
22+
*
23+
* Included:
24+
*
25+
* ```
26+
* .foo\\:pseudo-selector {}
27+
* .foo\\\\:pseudo-selector {}
28+
* ```
29+
*/
30+
export const EXCLUDED_PSEUDO_ESCAPE_SEQUENCE = '(?<=(?<!\\\\)(?:\\\\\\\\)*)';
31+
932
// Dynamic pseudo-classes
1033
// @see https://www.w3.org/TR/2018/REC-selectors-3-20181106/#dynamic-pseudos
1134
export const PSEUDO_STATES = {

code/addons/pseudo-states/src/preview/rewriteStyleSheet.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,30 @@ describe('rewriteStyleSheet', () => {
390390
);
391391
});
392392

393+
it('skips escaped pseudo-selectors "\\:hover"', () => {
394+
const sheet = new Sheet('a\\:hover { color: red }');
395+
rewriteStyleSheet(sheet as any);
396+
expect(sheet.cssRules.length).toEqual(1);
397+
expect(sheet.cssRules[0].cssText).toEqual('a\\:hover { color: red }');
398+
expect(sheet.cssRules[0].selectorText).toEqual('a\\:hover');
399+
});
400+
401+
it('supports "\\\\:hover"', () => {
402+
const sheet = new Sheet('.btn\\\\:hover { color: red }');
403+
rewriteStyleSheet(sheet as any);
404+
expect(sheet.cssRules[0].cssText).toEqual(
405+
'.btn\\\\:hover, .btn\\\\.pseudo-hover, .pseudo-hover-all .btn\\\\ { color: red }'
406+
);
407+
});
408+
409+
it('supports selectors with escaped and unescaped pseudo-selectors', () => {
410+
const sheet = new Sheet('.foo\\:hover\\:red:hover { color: red }');
411+
rewriteStyleSheet(sheet as any);
412+
expect(sheet.cssRules[0].cssText).toEqual(
413+
'.foo\\:hover\\:red:hover, .foo\\:hover\\:red.pseudo-hover, .pseudo-hover-all .foo\\:hover\\:red { color: red }'
414+
);
415+
});
416+
393417
it('override correct rules with media query present', () => {
394418
const sheet = new Sheet(
395419
`@media (max-width: 790px) {

code/addons/pseudo-states/src/preview/rewriteStyleSheet.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
import { EXCLUDED_PSEUDO_ELEMENT_PATTERNS, PSEUDO_STATES } from '../constants';
1+
import {
2+
EXCLUDED_PSEUDO_ELEMENT_PATTERNS,
3+
EXCLUDED_PSEUDO_ESCAPE_SEQUENCE,
4+
PSEUDO_STATES,
5+
} from '../constants';
26
import { splitSelectors } from './splitSelectors';
37

48
const pseudoStates = Object.values(PSEUDO_STATES);
5-
const pseudoStatesPattern = `:(${pseudoStates.join('|')})`;
9+
const pseudoStatesPattern = `${EXCLUDED_PSEUDO_ESCAPE_SEQUENCE}:(${pseudoStates.join('|')})`;
610
const matchOne = new RegExp(pseudoStatesPattern);
711
const matchAll = new RegExp(pseudoStatesPattern, 'g');
812

@@ -21,7 +25,7 @@ const replacePseudoStates = (selector: string, allClass?: boolean) => {
2125
return pseudoStates.reduce(
2226
(acc, state) =>
2327
acc.replace(
24-
new RegExp(`${negativeLookbehind}:${state}`, 'g'),
28+
new RegExp(`${negativeLookbehind}${EXCLUDED_PSEUDO_ESCAPE_SEQUENCE}:${state}`, 'g'),
2529
`.pseudo-${state}${allClass ? '-all' : ''}`
2630
),
2731
selector

code/addons/vitest/src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const TEST_PROVIDER_ID = `${ADDON_ID}/test-provider`;
1313
export const STORYBOOK_ADDON_TEST_CHANNEL = 'STORYBOOK_ADDON_TEST_CHANNEL';
1414

1515
export const TUTORIAL_VIDEO_LINK = 'https://youtu.be/Waht9qq7AoA';
16-
export const DOCUMENTATION_LINK = 'writing-tests/vitest-addon';
16+
export const DOCUMENTATION_LINK = 'writing-tests/integrations/vitest-addon';
1717
export const DOCUMENTATION_FATAL_ERROR_LINK = `${DOCUMENTATION_LINK}#what-happens-if-vitest-itself-has-an-error`;
1818

1919
export const COVERAGE_DIRECTORY = 'coverage';

code/addons/vitest/src/node/vitest-manager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ export class VitestManager {
5656
coverage
5757
? {
5858
enabled: true,
59-
clean: false,
60-
cleanOnRerun: false,
59+
clean: true,
60+
cleanOnRerun: true,
6161
reportOnFailure: true,
6262
reporter: [['html', {}], storybookCoverageReporter],
6363
reportsDirectory: resolvePathInStorybookCache(COVERAGE_DIRECTORY),

code/addons/vitest/src/postinstall.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,9 @@ export default async function postInstall(options: PostinstallOptions) {
325325
`
326326
);
327327

328-
const vitestWorkspaceFile = await findFile('vitest.workspace', ['.ts', '.js', '.json']);
328+
const vitestWorkspaceFile =
329+
(await findFile('vitest.workspace', ['.ts', '.js', '.json'])) ||
330+
(await findFile('vitest.projects', ['.ts', '.js', '.json']));
329331
const viteConfigFile = await findFile('vite.config');
330332
const vitestConfigFile = await findFile('vitest.config');
331333
const vitestShimFile = await findFile('vitest.shims.d');

code/addons/vitest/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export interface TestParameters {
66
/**
77
* Test addon configuration
88
*
9-
* @see https://storybook.js.org/docs/next/writing-tests/vitest-addon
9+
* @see https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
1010
*/
1111
test: {
1212
/** Ignore unhandled errors during test execution */

code/addons/vitest/src/updateVitestFile.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ describe('updateConfigFile', () => {
4343
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
4444
const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
4545
46-
// More info at: https://storybook.js.org/docs/next/writing-tests/vitest-addon
46+
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
4747
export default defineConfig({
4848
plugins: [react()],
4949
test: {
@@ -52,7 +52,7 @@ describe('updateConfigFile', () => {
5252
extends: true,
5353
plugins: [
5454
// The plugin will run tests for the stories defined in your Storybook config
55-
// See options at: https://storybook.js.org/docs/next/writing-tests/vitest-addon#storybooktest
55+
// See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
5656
storybookTest({
5757
configDir: path.join(dirname, '.storybook')
5858
})],
@@ -106,7 +106,7 @@ describe('updateConfigFile', () => {
106106
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
107107
const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
108108
109-
// More info at: https://storybook.js.org/docs/next/writing-tests/vitest-addon
109+
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
110110
export default {
111111
plugins: [react()],
112112
test: {
@@ -115,7 +115,7 @@ describe('updateConfigFile', () => {
115115
extends: true,
116116
plugins: [
117117
// The plugin will run tests for the stories defined in your Storybook config
118-
// See options at: https://storybook.js.org/docs/next/writing-tests/vitest-addon#storybooktest
118+
// See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
119119
storybookTest({
120120
configDir: path.join(dirname, '.storybook')
121121
})],
@@ -195,7 +195,7 @@ describe('updateConfigFile', () => {
195195
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
196196
const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
197197
198-
// More info at: https://storybook.js.org/docs/next/writing-tests/vitest-addon
198+
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
199199
export default defineConfig({
200200
plugins: [react()],
201201
test: {
@@ -204,7 +204,7 @@ describe('updateConfigFile', () => {
204204
extends: true,
205205
plugins: [
206206
// The plugin will run tests for the stories defined in your Storybook config
207-
// See options at: https://storybook.js.org/docs/next/writing-tests/vitest-addon#storybooktest
207+
// See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
208208
storybookTest({
209209
configDir: path.join(dirname, '.storybook')
210210
})],
@@ -255,15 +255,15 @@ describe('updateConfigFile', () => {
255255
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
256256
const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
257257
258-
// More info at: https://storybook.js.org/docs/next/writing-tests/vitest-addon
258+
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
259259
export default defineConfig({
260260
plugins: [react()],
261261
test: {
262262
workspace: [{
263263
extends: true,
264264
plugins: [
265265
// The plugin will run tests for the stories defined in your Storybook config
266-
// See options at: https://storybook.js.org/docs/next/writing-tests/vitest-addon#storybooktest
266+
// See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
267267
storybookTest({
268268
configDir: path.join(dirname, '.storybook')
269269
})],
@@ -306,12 +306,12 @@ describe('updateWorkspaceFile', () => {
306306
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
307307
const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
308308
309-
// More info at: https://storybook.js.org/docs/next/writing-tests/vitest-addon
309+
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
310310
export default ['packages/*', 'ROOT_CONFIG', {
311311
extends: '',
312312
plugins: [
313313
// The plugin will run tests for the stories defined in your Storybook config
314-
// See options at: https://storybook.js.org/docs/next/writing-tests/vitest-addon#storybooktest
314+
// See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
315315
storybookTest({
316316
configDir: path.join(dirname, '.storybook')
317317
})],
@@ -352,12 +352,12 @@ describe('updateWorkspaceFile', () => {
352352
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
353353
const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
354354
355-
// More info at: https://storybook.js.org/docs/next/writing-tests/vitest-addon
355+
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
356356
export default defineWorkspace(['packages/*', 'ROOT_CONFIG', {
357357
extends: '',
358358
plugins: [
359359
// The plugin will run tests for the stories defined in your Storybook config
360-
// See options at: https://storybook.js.org/docs/next/writing-tests/vitest-addon#storybooktest
360+
// See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
361361
storybookTest({
362362
configDir: path.join(dirname, '.storybook')
363363
})],

code/addons/vitest/templates/vitest.config.template.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
88
const dirname =
99
typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
1010

11-
// More info at: https://storybook.js.org/docs/next/writing-tests/vitest-addon
11+
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
1212
export default defineConfig({
1313
test: {
1414
workspace: [
1515
{
1616
extends: true,
1717
plugins: [
1818
// The plugin will run tests for the stories defined in your Storybook config
19-
// See options at: https://storybook.js.org/docs/next/writing-tests/vitest-addon#storybooktest
19+
// See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
2020
storybookTest({ configDir: path.join(dirname, 'CONFIG_DIR') }),
2121
],
2222
test: {

code/addons/vitest/templates/vitest.workspace.template.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
88
const dirname =
99
typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
1010

11-
// More info at: https://storybook.js.org/docs/next/writing-tests/vitest-addon
11+
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
1212
export default defineWorkspace([
1313
'ROOT_CONFIG',
1414
{
1515
extends: 'EXTENDS_WORKSPACE',
1616
plugins: [
1717
// The plugin will run tests for the stories defined in your Storybook config
18-
// See options at: https://storybook.js.org/docs/next/writing-tests/vitest-addon#storybooktest
18+
// See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
1919
storybookTest({ configDir: path.join(dirname, 'CONFIG_DIR') }),
2020
],
2121
test: {

code/core/src/common/presets.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,28 @@ export function filterPresetsConfig(presetsConfig: PresetConfig[]): PresetConfig
3939
});
4040
}
4141

42-
function resolvePathToMjs(filePath: string): string {
43-
const { dir, name } = parse(filePath);
42+
function resolvePathToESM(filePath: string): string {
43+
const { dir, name, ext } = parse(filePath);
44+
if (ext === '.mjs') {
45+
return filePath;
46+
}
4447
const mjsPath = join(dir, `${name}.mjs`);
4548
if (safeResolve(mjsPath)) {
4649
return mjsPath;
4750
}
51+
if (ext === '.cjs') {
52+
/*
53+
If the file is a CJS file, try to resolve the ESM version instead.
54+
We must assume that in the case that NO .mjs file exists, but a .cjs file does, the package is type="module"
55+
This is the case for addon-kit, which distributes both preview.cjs and preview.js for Jest compatibility
56+
and in that situation we want to prefer the .js version.
57+
*/
58+
const jsPath = join(dir, `${name}.js`);
59+
if (safeResolve(jsPath)) {
60+
return jsPath;
61+
}
62+
}
63+
4864
return filePath;
4965
}
5066

@@ -92,7 +108,7 @@ export const resolveAddonName = (
92108
// we remove the extension
93109
// this is a bit of a hack to try to find .mjs files
94110
// node can only ever resolve .js files; it does not look at the exports field in package.json
95-
managerEntries: [resolvePathToMjs(join(fdir, fname))],
111+
managerEntries: [resolvePathToESM(join(fdir, fname))],
96112
};
97113
}
98114
if (name.match(/\/(preset)(\.(js|mjs|ts|tsx|jsx))?$/)) {
@@ -117,11 +133,11 @@ export const resolveAddonName = (
117133
* broken in such cases, because it does not process absolute paths, and it will try to import
118134
* from the bare import, breaking in pnp/pnpm.
119135
*/
120-
const absolutizeExport = (exportName: string, preferMJS: boolean) => {
136+
const absolutizeExport = (exportName: string, preferESM: boolean) => {
121137
const found = resolve(`${name}${exportName}`);
122138

123139
if (found) {
124-
return preferMJS ? resolvePathToMjs(found) : found;
140+
return preferESM ? resolvePathToESM(found) : found;
125141
}
126142
return undefined;
127143
};

code/core/src/component-testing/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export const ADDON_ID = 'storybook/interactions';
22
export const PANEL_ID = `${ADDON_ID}/panel`;
33

4-
export const DOCUMENTATION_LINK = 'writing-tests/test-addon';
4+
export const DOCUMENTATION_LINK = 'writing-tests/integrations/vitest-addon';
55
export const DOCUMENTATION_DISCREPANCY_LINK = `${DOCUMENTATION_LINK}#what-happens-when-there-are-different-test-results-in-multiple-environments`;
66
export const DOCUMENTATION_PLAY_FUNCTION_LINK =
77
'writing-stories/play-function#writing-stories-with-the-play-function';

0 commit comments

Comments
 (0)