From 3f45de52d1b6cf44fab3c31bf751e22a4f0f84c0 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 12 Nov 2025 14:18:24 +0100 Subject: [PATCH 1/6] Use fixed stack trace in errors in stories --- .../stories/docspage/error.stories.ts | 12 ++++++- .../components/sidebar/Refs.stories.tsx | 33 +++++++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/code/addons/docs/template/stories/docspage/error.stories.ts b/code/addons/docs/template/stories/docspage/error.stories.ts index 5b3ebdf2455a..7114a8a65969 100644 --- a/code/addons/docs/template/stories/docspage/error.stories.ts +++ b/code/addons/docs/template/stories/docspage/error.stories.ts @@ -1,3 +1,4 @@ +/* eslint-disable local-rules/no-uncategorized-errors */ export default { component: globalThis.__TEMPLATE_COMPONENTS__.Button, tags: ['autodocs', '!test', '!vitest'], @@ -9,7 +10,16 @@ export default { export const ErrorStory = { decorators: [ () => { - throw new Error('Story did something wrong'); + const err = new Error('Story did something wrong'); + err.stack = ` + at errorStory (/sb-preview/file.js:000:0001) + at hookified (/sb-preview/file.js:000:0001) + at defaultDecorateStory (/sb-preview/file.js:000:0001) + at jsxDecorator (/assets/file.js:000:0001) + at hookified (/sb-preview/file.js:000:0001) + at decorateStory (/sb-preview/file.js:000:0001) + `; + throw err; }, ], }; diff --git a/code/core/src/manager/components/sidebar/Refs.stories.tsx b/code/core/src/manager/components/sidebar/Refs.stories.tsx index f2f47012289b..f649104ed8f6 100644 --- a/code/core/src/manager/components/sidebar/Refs.stories.tsx +++ b/code/core/src/manager/components/sidebar/Refs.stories.tsx @@ -1,9 +1,11 @@ +/* eslint-disable local-rules/no-uncategorized-errors */ import React from 'react'; -import type { StoryAnnotations } from 'storybook/internal/csf'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { ManagerContext } from 'storybook/manager-api'; import { fn, userEvent, within } from 'storybook/test'; +import { dedent } from 'ts-dedent'; import { standardData as standardHeaderData } from './Heading.stories'; import { IconSymbols } from './IconSymbols'; @@ -22,22 +24,24 @@ const managerContext = { }, } as any; -export default { +const meta = { component: Ref, title: 'Sidebar/Refs', excludeStories: /.*Data$/, parameters: { layout: 'fullscreen' }, globals: { sb_theme: 'side-by-side' }, decorators: [ - (storyFn: any) => ( + (storyFn) => ( {storyFn()} ), - (storyFn: any) =>
{storyFn()}
, + (storyFn) =>
{storyFn()}
, ], -}; +} satisfies Meta; + +export default meta; const { menu } = standardHeaderData; const filteredIndex = mockDataset.withRoot; @@ -49,7 +53,16 @@ export const loadingData = { menu, filteredIndex: {} }; // @ts-expect-error (non strict) const indexError: Error = (() => { try { - throw new Error('There was a severe problem'); + const err = new Error('There was a severe problem'); + err.stack = dedent` + at errorStory (/sb-preview/file.js:000:0001) + at hookified (/sb-preview/file.js:000:0001) + at defaultDecorateStory (/sb-preview/file.js:000:0001) + at jsxDecorator (/assets/file.js:000:0001) + at hookified (/sb-preview/file.js:000:0001) + at decorateStory (/sb-preview/file.js:000:0001) + `; + throw err; } catch (e) { return e; } @@ -282,7 +295,7 @@ export const ErroredMobile = () => ( /> ); ErroredMobile.globals = { sb_theme: 'stacked', viewport: { value: 'mobile1' } }; -export const ErroredWithErrorOpen: StoryAnnotations = { +export const ErroredWithErrorOpen: StoryObj = { render: () => Errored(), play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -290,7 +303,7 @@ export const ErroredWithErrorOpen: StoryAnnotations = { await userEvent.click(button); }, }; -export const ErroredMobileWithErrorOpen: StoryAnnotations = { +export const ErroredMobileWithErrorOpen: StoryObj = { render: () => ErroredMobile(), globals: { sb_theme: 'stacked', viewport: { value: 'mobile1' } }, play: async ({ canvasElement }) => { @@ -299,7 +312,7 @@ export const ErroredMobileWithErrorOpen: StoryAnnotations = { await userEvent.click(button); }, }; -export const ErroredWithIndicatorOpen: StoryAnnotations = { +export const ErroredWithIndicatorOpen: StoryObj = { render: () => Errored(), play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -307,7 +320,7 @@ export const ErroredWithIndicatorOpen: StoryAnnotations = { await userEvent.click(button); }, }; -export const ErroredMobileWithIndicatorOpen: StoryAnnotations = { +export const ErroredMobileWithIndicatorOpen: StoryObj = { render: () => ErroredMobile(), globals: { sb_theme: 'stacked', viewport: { value: 'mobile1' } }, play: async ({ canvasElement }) => { From 9cff188e9cf27af83ea5eead88ba7c4104480287 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 12 Nov 2025 15:51:04 +0100 Subject: [PATCH 2/6] try to get less flake --- code/addons/docs/src/blocks/blocks/Stories.stories.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/addons/docs/src/blocks/blocks/Stories.stories.tsx b/code/addons/docs/src/blocks/blocks/Stories.stories.tsx index 98576f0892b6..0164ad82e7d8 100644 --- a/code/addons/docs/src/blocks/blocks/Stories.stories.tsx +++ b/code/addons/docs/src/blocks/blocks/Stories.stories.tsx @@ -7,6 +7,9 @@ const meta = { parameters: { layout: 'fullscreen', docsStyles: true, + chromatic: { + delay: 2000, + }, }, } satisfies Meta; From 709bbf1cae44c2b678529d8b4090c54726b0d389 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 13 Nov 2025 13:28:56 +0100 Subject: [PATCH 3/6] fix flake --- code/core/template/stories/mount-in-play.stories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/core/template/stories/mount-in-play.stories.ts b/code/core/template/stories/mount-in-play.stories.ts index 5906b34ea6a9..59bc31384b9e 100644 --- a/code/core/template/stories/mount-in-play.stories.ts +++ b/code/core/template/stories/mount-in-play.stories.ts @@ -20,6 +20,6 @@ export const MountShouldBeDestructured = { } catch (e) { error = e; } - await expect(error?.name).toContain('MountMustBeDestructuredError'); + await expect(error?.name).toContain('SB_PREVIEW_API_0012'); }, }; From 79665ee97a9ac5d1db0d636af7644819ad9312e0 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Sat, 15 Nov 2025 16:54:41 +0100 Subject: [PATCH 4/6] Revert "fix flake" This reverts commit 709bbf1cae44c2b678529d8b4090c54726b0d389. --- code/core/template/stories/mount-in-play.stories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/core/template/stories/mount-in-play.stories.ts b/code/core/template/stories/mount-in-play.stories.ts index 59bc31384b9e..5906b34ea6a9 100644 --- a/code/core/template/stories/mount-in-play.stories.ts +++ b/code/core/template/stories/mount-in-play.stories.ts @@ -20,6 +20,6 @@ export const MountShouldBeDestructured = { } catch (e) { error = e; } - await expect(error?.name).toContain('SB_PREVIEW_API_0012'); + await expect(error?.name).toContain('MountMustBeDestructuredError'); }, }; From e36c0396b673a5bc796676087e36e0a2af76ed2b Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Sat, 15 Nov 2025 17:00:58 +0100 Subject: [PATCH 5/6] debug --- .../workflows/trigger-circle-ci-workflow.yml | 106 +++++++++++++++--- 1 file changed, 93 insertions(+), 13 deletions(-) diff --git a/.github/workflows/trigger-circle-ci-workflow.yml b/.github/workflows/trigger-circle-ci-workflow.yml index 7b1cedda19f1..c8142d3633f4 100644 --- a/.github/workflows/trigger-circle-ci-workflow.yml +++ b/.github/workflows/trigger-circle-ci-workflow.yml @@ -40,19 +40,99 @@ jobs: get-parameters: if: github.repository_owner == 'storybookjs' runs-on: ubuntu-latest + # NB: We'll set the job output from the final step (id: set_workflow). steps: - - if: github.event_name == 'pull_request_target' && (contains(github.event.pull_request.labels.*.name, 'ci:normal')) - run: echo "workflow=normal" >> $GITHUB_ENV - - if: github.event_name == 'pull_request_target' && (contains(github.event.pull_request.labels.*.name, 'ci:docs')) - run: echo "workflow=docs" >> $GITHUB_ENV - - if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'ci:merged') - run: echo "workflow=merged" >> $GITHUB_ENV - - if: github.event_name == 'pull_request_target' && (contains(github.event.pull_request.labels.*.name, 'ci:daily')) - run: echo "workflow=daily" >> $GITHUB_ENV + - name: Reset workflow (start clean) + run: | + echo "Resetting workflow env" + # ensure workflow env var is empty for the job + echo "workflow=" >> $GITHUB_ENV + + - name: Debug - show github context + run: | + echo "=== GITHUB CONTEXT / EVENT INFO ===" + echo "event_name: $GITHUB_EVENT_NAME" + echo "event.action: ${{ github.event.action || 'null' }}" + echo "pull_request exists? : ${{ github.event.pull_request != null }}" + echo "---- full event JSON (truncated to 20000 chars) ----" + # for readability, print parsed JSON (toJSON is safe here) + jq -C . <<<"${{ toJSON(github.event) }}" | sed -n '1,200p' + + - name: Determine workflow from labels on pull_request_target labeled event + if: github.event_name == 'pull_request_target' && github.event.action == 'labeled' + run: | + echo "Labeled event detected" + echo "Added label: ${{ github.event.label.name }}" + case "${{ github.event.label.name }}" in + ci:normal) echo "workflow=normal" >> $GITHUB_ENV ;; + ci:docs) echo "workflow=docs" >> $GITHUB_ENV ;; + ci:merged) echo "workflow=merged" >> $GITHUB_ENV ;; + ci:daily) echo "workflow=daily" >> $GITHUB_ENV ;; + *) + echo "Label is not a ci: label — leaving workflow empty" + ;; + esac + + - name: Determine workflow from labels on push event + if: github.event_name == 'push' && github.event.pull_request != null + run: | + echo "Push event with associated pull_request detected" + # Collect labels from the embedded pull_request JSON + LABELS=$(jq -r '.pull_request.labels[].name' <<<"${{ toJSON(github.event) }}" 2>/dev/null || true) + echo "PR labels: $LABELS" + for label in $LABELS; do + case "$label" in + ci:normal) + echo "Matched ci:normal" + echo "workflow=normal" >> $GITHUB_ENV + break + ;; + ci:docs) + echo "Matched ci:docs" + echo "workflow=docs" >> $GITHUB_ENV + break + ;; + ci:merged) + echo "Matched ci:merged" + echo "workflow=merged" >> $GITHUB_ENV + break + ;; + ci:daily) + echo "Matched ci:daily" + echo "workflow=daily" >> $GITHUB_ENV + break + ;; + esac + done + + - name: Finalize workflow output and debug + id: set_workflow + run: | + echo "=== Finalize and debug workflow value ===" + # Show what was written into the $GITHUB_ENV file (last lines containing workflow) + echo "-- GITHUB_ENV contents for workflow --" + grep '^workflow=' $GITHUB_ENV || echo "(no workflow entry found in GITHUB_ENV)" + + # The environment variable 'workflow' should now be available to steps. + echo "ENV workflow (the value we will publish): '${workflow}'" + + # For extra safety convert literal 'workflow=' to empty string + # and set the job output explicitly via GITHUB_OUTPUT + # (this makes needs.get-parameters.outputs.workflow deterministic) + # If workflow is unset, this will write an empty value which is what we want. + echo "workflow=${workflow}" >> $GITHUB_OUTPUT + + if [ -z "${workflow}" ]; then + echo "FINAL STATE: no ci:* workflow selected (empty)" + else + echo "FINAL STATE: workflow='${workflow}'" + fi + + # Make job outputs come from the step (set_workflow) outputs: - workflow: ${{ env.workflow }} - ghBaseBranch: ${{ github.event.pull_request.base.ref }} - ghPrNumber: ${{ github.event.pull_request.number }} + workflow: ${{ steps.set_workflow.outputs.workflow }} + ghBaseBranch: ${{ github.event.pull_request && github.event.pull_request.base.ref || '' }} + ghPrNumber: ${{ github.event.pull_request && github.event.pull_request.number || '' }} trigger-circle-ci-workflow: runs-on: ubuntu-latest @@ -62,7 +142,7 @@ jobs: - name: Trigger Normal tests uses: fjogeleit/http-request-action@v1 with: - url: 'https://circleci.com/api/v2/project/gh/storybookjs/storybook/pipeline' - method: 'POST' + url: "https://circleci.com/api/v2/project/gh/storybookjs/storybook/pipeline" + method: "POST" customHeaders: '{"Content-Type": "application/json", "Circle-Token": "${{ secrets.CIRCLE_CI_TOKEN }}"}' data: '{ "branch": "${{needs.get-branch.outputs.branch}}", "parameters": ${{toJson(needs.get-parameters.outputs)}} }' From aef4ddf8c36f6f19f1e8e1de8514b83a276244a2 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Sat, 15 Nov 2025 17:03:11 +0100 Subject: [PATCH 6/6] Revert "debug" This reverts commit e36c0396b673a5bc796676087e36e0a2af76ed2b. --- .../workflows/trigger-circle-ci-workflow.yml | 106 +++--------------- 1 file changed, 13 insertions(+), 93 deletions(-) diff --git a/.github/workflows/trigger-circle-ci-workflow.yml b/.github/workflows/trigger-circle-ci-workflow.yml index c8142d3633f4..7b1cedda19f1 100644 --- a/.github/workflows/trigger-circle-ci-workflow.yml +++ b/.github/workflows/trigger-circle-ci-workflow.yml @@ -40,99 +40,19 @@ jobs: get-parameters: if: github.repository_owner == 'storybookjs' runs-on: ubuntu-latest - # NB: We'll set the job output from the final step (id: set_workflow). steps: - - name: Reset workflow (start clean) - run: | - echo "Resetting workflow env" - # ensure workflow env var is empty for the job - echo "workflow=" >> $GITHUB_ENV - - - name: Debug - show github context - run: | - echo "=== GITHUB CONTEXT / EVENT INFO ===" - echo "event_name: $GITHUB_EVENT_NAME" - echo "event.action: ${{ github.event.action || 'null' }}" - echo "pull_request exists? : ${{ github.event.pull_request != null }}" - echo "---- full event JSON (truncated to 20000 chars) ----" - # for readability, print parsed JSON (toJSON is safe here) - jq -C . <<<"${{ toJSON(github.event) }}" | sed -n '1,200p' - - - name: Determine workflow from labels on pull_request_target labeled event - if: github.event_name == 'pull_request_target' && github.event.action == 'labeled' - run: | - echo "Labeled event detected" - echo "Added label: ${{ github.event.label.name }}" - case "${{ github.event.label.name }}" in - ci:normal) echo "workflow=normal" >> $GITHUB_ENV ;; - ci:docs) echo "workflow=docs" >> $GITHUB_ENV ;; - ci:merged) echo "workflow=merged" >> $GITHUB_ENV ;; - ci:daily) echo "workflow=daily" >> $GITHUB_ENV ;; - *) - echo "Label is not a ci: label — leaving workflow empty" - ;; - esac - - - name: Determine workflow from labels on push event - if: github.event_name == 'push' && github.event.pull_request != null - run: | - echo "Push event with associated pull_request detected" - # Collect labels from the embedded pull_request JSON - LABELS=$(jq -r '.pull_request.labels[].name' <<<"${{ toJSON(github.event) }}" 2>/dev/null || true) - echo "PR labels: $LABELS" - for label in $LABELS; do - case "$label" in - ci:normal) - echo "Matched ci:normal" - echo "workflow=normal" >> $GITHUB_ENV - break - ;; - ci:docs) - echo "Matched ci:docs" - echo "workflow=docs" >> $GITHUB_ENV - break - ;; - ci:merged) - echo "Matched ci:merged" - echo "workflow=merged" >> $GITHUB_ENV - break - ;; - ci:daily) - echo "Matched ci:daily" - echo "workflow=daily" >> $GITHUB_ENV - break - ;; - esac - done - - - name: Finalize workflow output and debug - id: set_workflow - run: | - echo "=== Finalize and debug workflow value ===" - # Show what was written into the $GITHUB_ENV file (last lines containing workflow) - echo "-- GITHUB_ENV contents for workflow --" - grep '^workflow=' $GITHUB_ENV || echo "(no workflow entry found in GITHUB_ENV)" - - # The environment variable 'workflow' should now be available to steps. - echo "ENV workflow (the value we will publish): '${workflow}'" - - # For extra safety convert literal 'workflow=' to empty string - # and set the job output explicitly via GITHUB_OUTPUT - # (this makes needs.get-parameters.outputs.workflow deterministic) - # If workflow is unset, this will write an empty value which is what we want. - echo "workflow=${workflow}" >> $GITHUB_OUTPUT - - if [ -z "${workflow}" ]; then - echo "FINAL STATE: no ci:* workflow selected (empty)" - else - echo "FINAL STATE: workflow='${workflow}'" - fi - - # Make job outputs come from the step (set_workflow) + - if: github.event_name == 'pull_request_target' && (contains(github.event.pull_request.labels.*.name, 'ci:normal')) + run: echo "workflow=normal" >> $GITHUB_ENV + - if: github.event_name == 'pull_request_target' && (contains(github.event.pull_request.labels.*.name, 'ci:docs')) + run: echo "workflow=docs" >> $GITHUB_ENV + - if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'ci:merged') + run: echo "workflow=merged" >> $GITHUB_ENV + - if: github.event_name == 'pull_request_target' && (contains(github.event.pull_request.labels.*.name, 'ci:daily')) + run: echo "workflow=daily" >> $GITHUB_ENV outputs: - workflow: ${{ steps.set_workflow.outputs.workflow }} - ghBaseBranch: ${{ github.event.pull_request && github.event.pull_request.base.ref || '' }} - ghPrNumber: ${{ github.event.pull_request && github.event.pull_request.number || '' }} + workflow: ${{ env.workflow }} + ghBaseBranch: ${{ github.event.pull_request.base.ref }} + ghPrNumber: ${{ github.event.pull_request.number }} trigger-circle-ci-workflow: runs-on: ubuntu-latest @@ -142,7 +62,7 @@ jobs: - name: Trigger Normal tests uses: fjogeleit/http-request-action@v1 with: - url: "https://circleci.com/api/v2/project/gh/storybookjs/storybook/pipeline" - method: "POST" + url: 'https://circleci.com/api/v2/project/gh/storybookjs/storybook/pipeline' + method: 'POST' customHeaders: '{"Content-Type": "application/json", "Circle-Token": "${{ secrets.CIRCLE_CI_TOKEN }}"}' data: '{ "branch": "${{needs.get-branch.outputs.branch}}", "parameters": ${{toJson(needs.get-parameters.outputs)}} }'