From c814305a1b2fed54a4d1fea467d07f87941f51bc Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Thu, 20 Feb 2025 13:16:02 +0100 Subject: [PATCH 1/5] feat: add --stepsApi configuraion for storybook v8 and v9 --- src/StoryWrightProcessor/GetStories.js | 17 +------- src/StoryWrightProcessor/GetStoriesV2.js | 40 +++++++++++++++++++ .../StoryWrightOptions.ts | 6 ++- .../StoryWrightProcessor.ts | 10 +++-- src/main.ts | 37 +++++++++++------ src/utils.ts | 19 ++++++++- 6 files changed, 94 insertions(+), 35 deletions(-) create mode 100644 src/StoryWrightProcessor/GetStoriesV2.js diff --git a/src/StoryWrightProcessor/GetStories.js b/src/StoryWrightProcessor/GetStories.js index b1b734b..bb9bc8f 100644 --- a/src/StoryWrightProcessor/GetStories.js +++ b/src/StoryWrightProcessor/GetStories.js @@ -1,23 +1,10 @@ // @ts-check -/** - * @typedef {{ - argTypeTargetsV7:boolean; - buildStoriesJson:boolean; - disallowImplicitActionsInRenderV8: boolean; - legacyDecoratorFileOrder: boolean; - storyStoreV7?: boolean; - warnOnLegacyHierarchySeparator: boolean - }} SbFeatures -*/ - - - getStoriesWithSteps(); function getStoriesWithSteps() { /** - * @type {SbFeatures} + * @type {import('../utils').StorybookFeatures} */ const storybookFeatures = window["FEATURES"]; @@ -103,7 +90,7 @@ function findSteps(res) { /** * - * @param {SbFeatures} features + * @param {import('../utils').StorybookFeatures} features * @returns {Promise>} */ function getPageStories(features) { diff --git a/src/StoryWrightProcessor/GetStoriesV2.js b/src/StoryWrightProcessor/GetStoriesV2.js new file mode 100644 index 0000000..8b4ad58 --- /dev/null +++ b/src/StoryWrightProcessor/GetStoriesV2.js @@ -0,0 +1,40 @@ +// @ts-check + +getStoriesWithSteps(); + +function getStoriesWithSteps() { + return getPageStories().then((stories) => { + /** + * @type {typeof stories} + */ + const storiesWithSteps = []; + /** + * @type {string[]} story ids that failed while processing parameters + */ + const errors = []; + for (let story of stories) { + try { + const steps = story.parameters?.storyWright.steps; + if (Array.isArray(steps)) { + story.steps = steps; + } + } catch (ex) { + errors.push(story["id"]); + console.error("Error processing 'parameters' of: " + story["id"]); + console.error(ex); + } + + storiesWithSteps.push(story); + } + + return { storiesWithSteps, errors }; + }); +} + +/** + * + * @returns {Promise>} + */ +function getPageStories() { + return window["__STORYBOOK_PREVIEW__"].extract(); +} diff --git a/src/StoryWrightProcessor/StoryWrightOptions.ts b/src/StoryWrightProcessor/StoryWrightOptions.ts index 0ff2869..e1d0006 100644 --- a/src/StoryWrightProcessor/StoryWrightOptions.ts +++ b/src/StoryWrightProcessor/StoryWrightOptions.ts @@ -12,5 +12,9 @@ export interface StoryWrightOptions { totalPartitions: number; waitTimeScreenshot: number; excludePatterns: Array; - bailOnStoriesError: boolean + bailOnStoriesError: boolean; + /** + * NOTE: `component` is deprecated and will be removed in next major. SB will no longer support exposing storyFn() so we won't be able to obtain dynamically steps from props. + */ + stepsApi: "component" | "parameters"; } diff --git a/src/StoryWrightProcessor/StoryWrightProcessor.ts b/src/StoryWrightProcessor/StoryWrightProcessor.ts index 1e09928..39ab612 100644 --- a/src/StoryWrightProcessor/StoryWrightProcessor.ts +++ b/src/StoryWrightProcessor/StoryWrightProcessor.ts @@ -48,10 +48,12 @@ export class StoryWrightProcessor { let stories: Story[]; try { - const getStoriesScript = readFileSync( - join(__dirname, "GetStories.js"), - "utf8" - ); + const scriptKind = { + component: join(__dirname, "GetStories.js"), + parameters: join(__dirname, "GetStoriesV2.js"), + }; + const getStoriesScriptPath = scriptKind[options.stepsApi]; + const getStoriesScript = readFileSync(getStoriesScriptPath, "utf8"); const { storiesWithSteps, errors } = await page.evaluate<{ storiesWithSteps: Story[]; errors: string[]; diff --git a/src/main.ts b/src/main.ts index b87b106..261a397 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,13 +12,13 @@ const args = argv .usage("Usage: $0 [options]") .example([ [ - "$0", - "Captures screenshot for all stories using default static storybook path dist/iframe.html" + "$0", + "Captures screenshot for all stories using default static storybook path dist/iframe.html", ], [ - "$0 -url https://localhost:5555 --browsers chromium", - "Captures screenshot for all stories from given storybook url for chromium browser" - ] + "$0 -url https://localhost:5555 --browsers chromium", + "Captures screenshot for all stories from given storybook url for chromium browser", + ], ]) .option("url", { alias: "storybookurl", @@ -52,7 +52,7 @@ const args = argv type: "array", coerce: (array) => { return array.flatMap((v) => v.split(",")); - } + }, }) .option("headless", { default: false, @@ -89,8 +89,7 @@ const args = argv .option("waitTimeScreenshot", { alias: "waitTimeScreenshot", default: 1000, - describe: - "Time to wait before taking screenshot", + describe: "Time to wait before taking screenshot", nargs: 1, type: "number", }) @@ -100,15 +99,26 @@ const args = argv "Fail process if errors occurred while processing Stories or during making screenshots. Useful to make sure that your VR Test are valid and in CI scenarios.", type: "boolean", }) - .strict(true) - .argv; - + .option("stepsApi", { + /** + * NOTE: next major will use `parameters` as default + */ + default: "component" as StoryWrightOptions["stepsApi"], + describe: [ + "Configure which API should be used to define Story Steps.", + "NOTE: 'component' will be removed in next major to support Storybook 9", + "NOTE: 'parameters' will work only with CSF3 format of your Stories. Decorators containing StoryWright component won't be processed", + ].join("\n"), + type: "string", + choices: ["component", "parameters"], + }) + .strict(true).argv; // When http(s) storybook url is passed no modification required. // When file path is provided it needs to be converted to absolute path and file:/// needs to be added to support firefox browser. //const url: string = - //args.url.indexOf("http") > -1 ? args.url : "file:///" + resolve(args.url); +//args.url.indexOf("http") > -1 ? args.url : "file:///" + resolve(args.url); console.log(`================ StoryWright params =================`); console.log(`Storybook url = ${args.url}`); @@ -135,7 +145,8 @@ const storyWrightOptions: StoryWrightOptions = { totalPartitions: args.totalPartitions, waitTimeScreenshot: args.waitTimeScreenshot, excludePatterns: args.excludePatterns, - bailOnStoriesError: args.bailOnStoriesError + bailOnStoriesError: args.bailOnStoriesError, + stepsApi: args.stepsApi, }; StoryWrightProcessor.process(storyWrightOptions); diff --git a/src/utils.ts b/src/utils.ts index 97c7e76..b999d7c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -14,8 +14,23 @@ export interface Story { tags: string[]; name: string; kind: string; - parameters?: import("./StoryWright/Steps").StoryParameters; - steps?: import('./StoryWright/Steps').Step[]; + parameters?: import("./StoryWright/Steps").StoryParameters; + steps?: import("./StoryWright/Steps").Step[]; + /** + * @deprecated - will be removed in next major. won't exist with `componentApi: 'parameters'` + */ storyFn?: () => unknown; [key: string]: unknown; } + +export interface StorybookFeatures { + /** + * @deprecated - will be removed in next major. SB v8 doesn't support this anymore + */ + argTypeTargetsV7: boolean; + buildStoriesJson: boolean; + disallowImplicitActionsInRenderV8: boolean; + legacyDecoratorFileOrder: boolean; + storyStoreV7?: boolean; + warnOnLegacyHierarchySeparator: boolean; +} From 6af4048edb97be2b432cb09aefdcd7fa49b4ff82 Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Thu, 20 Feb 2025 13:17:11 +0100 Subject: [PATCH 2/5] feat: bump version for new release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 352ae5c..ea8ff28 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "storywright", "description": "Storybook setup.", "license": "MIT", - "version": "0.0.27-storybook7.12", + "version": "0.0.27-storybook7.13", "main": "lib/index.js", "module": "lib/index.js", "typings": "lib/index.d.ts", From 06adc8c065b46d24b53359cb145a825e83386503 Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Thu, 20 Feb 2025 13:18:12 +0100 Subject: [PATCH 3/5] feat: increase sb support range to <10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ea8ff28..7e730f9 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ }, "peerDependencies": { "react": "^18.0.0 || ^17.0.0 || ^16.0.0", - "@storybook/preview-api": ">=7.0.0 <9.0.0" + "@storybook/preview-api": ">=7.0.0 <10.0.0" }, "devDependencies": { "@types/react": "^17.0.8", From 48a0164e4f508694b53e500e0345cb40469f6ee7 Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Tue, 25 Feb 2025 17:42:36 +0100 Subject: [PATCH 4/5] chore: update lock file --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8f6e172..e12547a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "storywright", - "version": "0.0.27-storybook7.12", + "version": "0.0.27-storybook7.13", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "storywright", - "version": "0.0.27-storybook7.12", + "version": "0.0.27-storybook7.13", "license": "MIT", "dependencies": { "playwright": "^1.34.3", @@ -25,7 +25,7 @@ "typescript": "^4.1.2" }, "peerDependencies": { - "@storybook/preview-api": ">=7.0.0 <9.0.0", + "@storybook/preview-api": ">=7.0.0 <10.0.0", "react": "^18.0.0 || ^17.0.0 || ^16.0.0" } }, From 6ffeef8c36e5eddc71597d157514fcee67e412ce Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Tue, 25 Feb 2025 17:45:05 +0100 Subject: [PATCH 5/5] ci: enable pr workflow --- .github/workflows/pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 26c60e6..4cc2360 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -6,7 +6,7 @@ name: PR build on: # Triggers the workflow on push or pull request events but only for the main branch pull_request: - branches: [main] + branches: [storybook7] workflow_dispatch: