Skip to content

Commit

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

Release: Prerelease 8.4.0-beta.4
  • Loading branch information
kasperpeulen authored Oct 30, 2024
2 parents 72b24f8 + a2c7d35 commit 69bd054
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 124 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 8.4.0-beta.4

- Addon Test: Improve Error Handling - [#29476](https://github.com/storybookjs/storybook/pull/29476), thanks @valentinpalkovic!
- Addon Test: Improve postinstall script - [#29479](https://github.com/storybookjs/storybook/pull/29479), thanks @yannbf!
- Addon Test: Throttle Vitest progress updates more heavily - [#29482](https://github.com/storybookjs/storybook/pull/29482), thanks @ghengeveld!
- CLI: Refactor NPMProxy error parsing logic - [#29459](https://github.com/storybookjs/storybook/pull/29459), thanks @yannbf!
- Core: Track test provider state in sessionStorage - [#29450](https://github.com/storybookjs/storybook/pull/29450), thanks @ghengeveld!
- Dependencies: Upgrade VTA to v3.2.0 to resolve peerDep conflict - [#29461](https://github.com/storybookjs/storybook/pull/29461), thanks @ghengeveld!

## 8.4.0-beta.3

- Addon Test: Only register testing module in Vite projects - [#29472](https://github.com/storybookjs/storybook/pull/29472), thanks @yannbf!
Expand Down
12 changes: 6 additions & 6 deletions code/addons/test/src/manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ const RelativeTime = ({ timestamp, testCount }: { timestamp: Date; testCount: nu
};

addons.register(ADDON_ID, (api) => {
if (globalThis.STORYBOOK_BUILDER?.includes('vite')) {
const storybookBuilder = (globalThis as any).STORYBOOK_BUILDER || '';
if (storybookBuilder.includes('vite')) {
const openAddonPanel = () => {
api.setSelectedPanel(PANEL_ID);
api.togglePanel(true);
Expand All @@ -94,10 +95,10 @@ addons.register(ADDON_ID, (api) => {
name: 'Component tests',
title: ({ crashed, failed }) =>
crashed || failed ? 'Component tests failed' : 'Component tests',
description: ({ failed, running, watching, progress, crashed, details }) => {
description: ({ failed, running, watching, progress, crashed, error }) => {
const [isModalOpen, setIsModalOpen] = useState(false);

const errorMessage = details?.error?.message;
const errorMessage = error?.message;

let message: string | React.ReactNode = 'Not run';

Expand All @@ -106,7 +107,7 @@ addons.register(ADDON_ID, (api) => {
? `Testing... ${progress.numPassedTests}/${progress.numTotalTests}`
: 'Starting...';
} else if (failed && !errorMessage) {
message = 'Component tests failed';
message = '';
} else if (crashed || (failed && errorMessage)) {
message = (
<>
Expand All @@ -116,7 +117,7 @@ addons.register(ADDON_ID, (api) => {
setIsModalOpen(true);
}}
>
{details?.error?.name || 'View full error'}
{error?.name || 'View full error'}
</LinkComponent>
</>
);
Expand Down Expand Up @@ -177,7 +178,6 @@ addons.register(ADDON_ID, (api) => {
),
} as Addon_TestProviderType<{
testResults: TestResult[];
error?: { message: string; name: string };
}>);
}

Expand Down
6 changes: 4 additions & 2 deletions code/addons/test/src/node/boot-test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,13 @@ const bootTestRunner = async (channel: Channel, initEvent?: string, initArgs?: a
killChild();
log(result.message);
log(result.error);
// eslint-disable-next-line local-rules/no-uncategorized-errors
const error = new Error(`${result.message}\n${result.error}`);
// Reject if the child process reports an error before it's ready
if (!ready) {
reject(new Error(`${result.message}\n${result.error}`));
reject(error);
} else {
reportFatalError(result.error);
reportFatalError(error);
}
} else {
channel.emit(result.type, ...result.args);
Expand Down
86 changes: 45 additions & 41 deletions code/addons/test/src/node/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class StorybookReporter implements Reporter {
sendReport: (payload: TestingModuleProgressReportPayload) => void;

constructor(private testManager: TestManager) {
this.sendReport = throttle((payload) => this.testManager.sendProgressReport(payload), 200);
this.sendReport = throttle((payload) => this.testManager.sendProgressReport(payload), 1000);
}

onInit(ctx: Vitest) {
Expand Down Expand Up @@ -190,51 +190,55 @@ export class StorybookReporter implements Reporter {
async onFinished() {
const unhandledErrors = this.ctx.state.getUnhandledErrors();

if (unhandledErrors?.length) {
this.testManager.reportFatalError(
`Vitest caught ${unhandledErrors.length} unhandled error${unhandledErrors?.length > 1 ? 's' : ''} during the test run.`,
unhandledErrors[0]
);
} else {
const isCancelled = this.ctx.isCancelling;
const report = this.getProgressReport(Date.now());
const isCancelled = this.ctx.isCancelling;
const report = this.getProgressReport(Date.now());

const testSuiteFailures = report.details.testResults.filter(
(t) => t.status === 'failed' && t.results.length === 0
);
const testSuiteFailures = report.details.testResults.filter(
(t) => t.status === 'failed' && t.results.length === 0
);

const reducedTestSuiteFailures = new Set<string>();

const reducedTestSuiteFailures = new Set<string>();
testSuiteFailures.forEach((t) => {
reducedTestSuiteFailures.add(t.message);
});

testSuiteFailures.forEach((t) => {
reducedTestSuiteFailures.add(t.message);
if (isCancelled) {
this.sendReport({
providerId: TEST_PROVIDER_ID,
status: 'cancelled',
...report,
});
} else if (reducedTestSuiteFailures.size > 0 || unhandledErrors.length > 0) {
const error =
reducedTestSuiteFailures.size > 0
? {
name: `${reducedTestSuiteFailures.size} component ${reducedTestSuiteFailures.size === 1 ? 'test' : 'tests'} failed`,
message: Array.from(reducedTestSuiteFailures).reduce(
(acc, curr) => `${acc}\n${curr}`,
''
),
}
: {
name: `${unhandledErrors.length} unhandled error${unhandledErrors?.length > 1 ? 's' : ''}`,
message: unhandledErrors
.map((e, index) => `[${index}]: ${(e as any).stack || (e as any).message}`)
.join('\n----------\n'),
};

if (isCancelled) {
this.sendReport({
providerId: TEST_PROVIDER_ID,
status: 'cancelled',
...report,
});
} else if (reducedTestSuiteFailures.size > 0) {
const message = Array.from(reducedTestSuiteFailures).reduce(
(acc, curr) => `${acc}\n${curr}`,
''
);
this.sendReport({
providerId: TEST_PROVIDER_ID,
status: 'failed',
error: {
name: `${reducedTestSuiteFailures.size} component ${reducedTestSuiteFailures.size === 1 ? 'test' : 'tests'} failed`,
message: message,
},
});
} else {
this.sendReport({
providerId: TEST_PROVIDER_ID,
status: 'success',
...report,
});
}
this.sendReport({
providerId: TEST_PROVIDER_ID,
status: 'failed',
details: report.details,
progress: report.progress,
error,
});
} else {
this.sendReport({
providerId: TEST_PROVIDER_ID,
status: 'success',
...report,
});
}

this.clearVitestState();
Expand Down
108 changes: 63 additions & 45 deletions code/addons/test/src/postinstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,43 +53,6 @@ export default async function postInstall(options: PostinstallOptions) {
// if Vitest is installed, we use the same version to keep consistency across Vitest packages
const vitestVersionToInstall = vitestVersionSpecifier ?? 'latest';

const addonInteractionsName = '@storybook/addon-interactions';
const interactionsAddon = info.addons.find((addon: string | { name: string }) => {
// account for addons as objects, as well as addons with PnP paths
const addonName = typeof addon === 'string' ? addon : addon.name;
return addonName.includes(addonInteractionsName);
});

if (!!interactionsAddon) {
let shouldUninstall = options.yes;
if (!options.yes) {
logger.plain(dedent`
We have detected that you're using ${addonInteractionsName}.
The Storybook test addon is a replacement for the interactions addon, so you must uninstall and unregister it in order to use the test addon correctly. This can be done automatically.
More info: ${picocolors.yellow('https://storybook.js.org/docs/writing-tests/test-addon')}
`);

const response = await prompts({
type: 'confirm',
name: 'shouldUninstall',
message: `Would you like me to remove and unregister ${addonInteractionsName}?`,
initial: true,
});

shouldUninstall = response.shouldUninstall;
}

if (shouldUninstall) {
await execa(
packageManager.getRemoteRunCommand(),
['storybook', 'remove', addonInteractionsName, '--package-manager', options.packageManager],
{
shell: true,
}
);
}
}
const annotationsImport = [
'@storybook/nextjs',
'@storybook/experimental-nextjs-vite',
Expand Down Expand Up @@ -122,9 +85,9 @@ export default async function postInstall(options: PostinstallOptions) {
`);
}

if (coercedVitestVersion && !satisfies(coercedVitestVersion, '>=2.0.0')) {
reasons.push(`
• The addon requires Vitest 2.0.0 or later. You are currently using ${vitestVersionSpecifier}.
if (coercedVitestVersion && !satisfies(coercedVitestVersion, '>=2.1.0')) {
reasons.push(dedent`
• The addon requires Vitest 2.1.0 or later. You are currently using ${picocolors.bold(vitestVersionSpecifier)}.
Please update your ${picocolors.bold(colors.pink('vitest'))} dependency and try again.
`);
}
Expand All @@ -145,7 +108,7 @@ export default async function postInstall(options: PostinstallOptions) {
);
reasons.push(
dedent`
To roll back the installation, remove ${picocolors.bold(colors.pink(ADDON_NAME))} from the "addons" array
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
in your main Storybook config file and remove the dependency from your package.json file.
`
);
Expand Down Expand Up @@ -180,6 +143,57 @@ export default async function postInstall(options: PostinstallOptions) {
return;
}

const addonInteractionsName = '@storybook/addon-interactions';
const interactionsAddon = info.addons.find((addon: string | { name: string }) => {
// account for addons as objects, as well as addons with PnP paths
const addonName = typeof addon === 'string' ? addon : addon.name;
return addonName.includes(addonInteractionsName);
});

if (!!interactionsAddon) {
let shouldUninstall = options.yes;
if (!options.yes) {
printInfo(
'⚠️ Attention',
dedent`
We have detected that you're using ${addonInteractionsName}.
The Storybook test addon is a replacement for the interactions addon, so you must uninstall and unregister it in order to use the test addon correctly. This can be done automatically.
More info: ${picocolors.cyan('https://storybook.js.org/docs/writing-tests/test-addon')}
`
);

const response = await prompts({
type: 'confirm',
name: 'shouldUninstall',
message: `Would you like me to remove and unregister ${addonInteractionsName}? Press N to abort the entire installation.`,
initial: true,
});

shouldUninstall = response.shouldUninstall;
}

if (shouldUninstall) {
await execa(
packageManager.getRemoteRunCommand(),
[
'storybook',
'remove',
addonInteractionsName,
'--package-manager',
options.packageManager,
'--config-dir',
options.configDir,
],
{
shell: true,
}
);
} else {
return;
}
}

const vitestInfo = getVitestPluginInfo(info.frameworkPackageName);

if (info.frameworkPackageName === '@storybook/nextjs') {
Expand Down Expand Up @@ -317,6 +331,8 @@ export default async function postInstall(options: PostinstallOptions) {
// If there's an existing config, we create a workspace file so we can run Storybook tests alongside.
const extname = path.extname(rootConfig);
const browserWorkspaceFile = path.resolve(dirname(rootConfig), `vitest.workspace${extname}`);
// to be set in vitest config
const vitestSetupFilePath = path.relative(path.dirname(browserWorkspaceFile), vitestSetupFile);

logger.line(1);
logger.plain(`${step} Creating a Vitest project workspace file:`);
Expand All @@ -335,7 +351,7 @@ export default async function postInstall(options: PostinstallOptions) {
extends: '${viteConfigFile ? relative(dirname(browserWorkspaceFile), viteConfigFile) : ''}',
plugins: [
// See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest
storybookTest(),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall}
storybookTest({ configDir: '${options.configDir}' }),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall}
],
test: {
name: 'storybook',
Expand All @@ -347,7 +363,7 @@ export default async function postInstall(options: PostinstallOptions) {
},
// Make sure to adjust this pattern to match your stories files.
include: ['**/*.stories.?(m)[jt]s?(x)'],
setupFiles: ['./.storybook/vitest.setup.ts'],
setupFiles: ['${vitestSetupFilePath}'],
},
},
]);
Expand All @@ -356,6 +372,8 @@ export default async function postInstall(options: PostinstallOptions) {
} else {
// If there's no existing Vitest/Vite config, we create a new Vitest config file.
const newVitestConfigFile = path.resolve('vitest.config.ts');
// to be set in vitest config
const vitestSetupFilePath = path.relative(path.dirname(newVitestConfigFile), vitestSetupFile);

logger.line(1);
logger.plain(`${step} Creating a Vitest project config file:`);
Expand All @@ -371,7 +389,7 @@ export default async function postInstall(options: PostinstallOptions) {
export default defineConfig({
plugins: [
// See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest
storybookTest(),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall}
storybookTest({ configDir: '${options.configDir}' }),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall}
],
test: {
name: 'storybook',
Expand All @@ -383,7 +401,7 @@ export default async function postInstall(options: PostinstallOptions) {
},
// Make sure to adjust this pattern to match your stories files.
include: ['**/*.stories.?(m)[jt]s?(x)'],
setupFiles: ['./.storybook/vitest.setup.ts'],
setupFiles: ['${vitestSetupFilePath}'],
},
});
`
Expand Down
1 change: 0 additions & 1 deletion code/addons/test/src/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export const experimental_serverChannel = async (channel: Channel, options: Opti
Information on how to upgrade here: ${picocolors.yellow('https://storybook.js.org/docs/get-started/frameworks/nextjs#with-vite')}\n
`);
}

return channel;
}

Expand Down
2 changes: 2 additions & 0 deletions code/addons/test/typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ interface ImportMetaEnv {
interface ImportMeta {
readonly env: ImportMetaEnv;
}

declare var STORYBOOK_BUILDER: string | undefined;
Loading

0 comments on commit 69bd054

Please sign in to comment.