diff --git a/.changeset/thin-experts-ring.md b/.changeset/thin-experts-ring.md new file mode 100644 index 00000000..13276359 --- /dev/null +++ b/.changeset/thin-experts-ring.md @@ -0,0 +1,6 @@ +--- +"@interactors/material-ui": patch +"@interactors/with-storybook": patch +--- + +Add Storybook addon `with-storybook` package diff --git a/package.json b/package.json index 36bca341..076893e8 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "packages/keyboard", "packages/html", "packages/material-ui", - "packages/with-cypress" + "packages/with-cypress", + "packages/with-storybook" ] }, "scripts": { diff --git a/packages/material-ui/.storybook/main.js b/packages/material-ui/.storybook/main.js index 6ec4a016..97f556eb 100644 --- a/packages/material-ui/.storybook/main.js +++ b/packages/material-ui/.storybook/main.js @@ -1,6 +1,11 @@ module.exports = { stories: ["../stories/**/*.stories.@(md|ts)x"], - addons: ["@storybook/addon-postcss", "@storybook/addon-essentials", '@storybook/addon-interactions'], + addons: [ + "@storybook/addon-postcss", + "@storybook/addon-essentials", + "@storybook/addon-interactions", + "@interactors/with-storybook", + ], features: { previewCsfV3: true, interactionsDebugger: true }, core: { builder: "webpack5" }, typescript: { reactDocgen: false }, diff --git a/packages/material-ui/package.json b/packages/material-ui/package.json index fbaf91c6..bf68cba8 100644 --- a/packages/material-ui/package.json +++ b/packages/material-ui/package.json @@ -66,6 +66,7 @@ }, "dependencies": { "effection": "^2.0.4", - "@interactors/html": "1.0.0-rc1.2" + "@interactors/html": "1.0.0-rc1.2", + "@interactors/with-storybook": "1.0.0-rc1.2" } } diff --git a/packages/material-ui/tsconfig.build.json b/packages/material-ui/tsconfig.build.json index 4429ddbe..11cbe46b 100644 --- a/packages/material-ui/tsconfig.build.json +++ b/packages/material-ui/tsconfig.build.json @@ -10,6 +10,7 @@ "types" ], "references": [ + { "path": "../globals/tsconfig.build.json" }, { "path": "../html/tsconfig.build.json" } ] } diff --git a/packages/with-storybook/.gitignore b/packages/with-storybook/.gitignore new file mode 100644 index 00000000..db4c6d9b --- /dev/null +++ b/packages/with-storybook/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules \ No newline at end of file diff --git a/packages/with-storybook/CHANGELOG.md b/packages/with-storybook/CHANGELOG.md new file mode 100644 index 00000000..7863f5e2 --- /dev/null +++ b/packages/with-storybook/CHANGELOG.md @@ -0,0 +1 @@ +# @interactors/with-storybook diff --git a/packages/with-storybook/README.md b/packages/with-storybook/README.md new file mode 100644 index 00000000..641d3c38 --- /dev/null +++ b/packages/with-storybook/README.md @@ -0,0 +1,13 @@ +## @interactors/with-storybook + +[![npm](https://img.shields.io/npm/v/@interactors/with-storybook.svg)](https://www.npmjs.com/package/@interactors/with-storybook) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Created by Frontside](https://img.shields.io/badge/created%20by-frontside-26abe8.svg)](https://frontside.com) +[![Chat on Discord](https://img.shields.io/discord/700803887132704931?Label=Discord)](https://discord.gg/mv4uxxcAKd) + +[Interactors][] are Page Objects for component libraries and design systems. +This package lets you use them seamlessly within [Storybook][] interactive stories. Learn more at +[https://frontside.com/interactors/docs/integrations#storybook](https://frontside.com/interactors/docs/integrations#storybook) + +[Interactors]: https://frontside.com/interactors +[Storybook]: https://storybook.js.org diff --git a/packages/with-storybook/package.json b/packages/with-storybook/package.json new file mode 100644 index 00000000..c1dbbf00 --- /dev/null +++ b/packages/with-storybook/package.json @@ -0,0 +1,46 @@ +{ + "name": "@interactors/with-storybook", + "version": "1.0.0-rc1.2", + "description": "Storybook addon integration for Interactors", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/thefrontside/interactors.git" + }, + "homepage": "https://frontside.com/interactors", + "author": "Frontside Engineering ", + "license": "MIT", + "files": [ + "dist/**/*", + "src/**/*", + "preset.js", + "README.md" + ], + "dependencies": { + "@interactors/globals": "^1.0.0-rc1.1" + }, + "peerDependencies": { + "@storybook/addon-interactions": "*" + }, + "scripts": { + "clean": "rm -rf dist *.tsbuildinfo", + "lint": "eslint \"src/**/*.ts\"", + "prepack": "tsc --build ./tsconfig.build.json && yarn prepack:es2015 && yarn prepack:commonjs", + "prepack:es2015": "tsc --project ./tsconfig.build.json --outdir dist/esm --module es2015", + "prepack:commonjs": "tsc --project ./tsconfig.build.json --outdir dist/cjs --module commonjs" + }, + "devDependencies": { + "@frontside/eslint-config": "^2.1.0", + "@frontside/tsconfig": "^1.2.0", + "@frontside/typescript": "^1.1.1" + }, + "volta": { + "node": "14.17.5", + "yarn": "1.22.11" + }, + "keywords": ["storybook", "addons", "interactors", "testing", "debug"], + "displayName": "Interactors inspector", + "icon": "https://frontside.com/interactors/img/interactors-logo@4x.png" +} diff --git a/packages/with-storybook/preset.js b/packages/with-storybook/preset.js new file mode 100644 index 00000000..aeb5343e --- /dev/null +++ b/packages/with-storybook/preset.js @@ -0,0 +1,5 @@ +module.exports = { + config(entry = []) { + return [...entry, require.resolve('./dist/esm/wrapper')]; + } +} diff --git a/packages/material-ui/.storybook/preview.tsx b/packages/with-storybook/src/wrapper.ts similarity index 84% rename from packages/material-ui/.storybook/preview.tsx rename to packages/with-storybook/src/wrapper.ts index 61be6234..5dbc4305 100644 --- a/packages/material-ui/.storybook/preview.tsx +++ b/packages/with-storybook/src/wrapper.ts @@ -13,8 +13,8 @@ addInteractionWrapper((perform, interaction) => { return perform; } return async () => { - const channel = addons.getChannel(); - const cancel = (event) => { + let channel = addons.getChannel(); + let cancel = (event: { newPhase?: 'aborted' | 'errored' }) => { if (!event.newPhase || event.newPhase == "aborted" || event.newPhase == "errored") { channel.off(Events.FORCE_REMOUNT, cancel); channel.off(Events.STORY_RENDER_PHASE_CHANGED, cancel); @@ -25,9 +25,10 @@ addInteractionWrapper((perform, interaction) => { channel.on(Events.FORCE_REMOUNT, cancel); channel.on(Events.STORY_RENDER_PHASE_CHANGED, cancel); try { + // @ts-expect-error Storybook hasn't exposed instrumenter's API to public, yet return await global.window.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER__.track( interaction.code(), - perform, + async () => perform(), [], { intercept: () => !(isRoot = false) } ); diff --git a/packages/with-storybook/tsconfig.build.json b/packages/with-storybook/tsconfig.build.json new file mode 100644 index 00000000..defb5be9 --- /dev/null +++ b/packages/with-storybook/tsconfig.build.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig-base.json", + "compilerOptions": { + "outDir": "dist/cjs", + "rootDir": "./src", + "declarationDir": "dist" + }, + "include": [ + "src/**/*.ts" + ], + "references": [ + { "path": "../globals/tsconfig.build.json" } + ] +} diff --git a/packages/with-storybook/tsconfig.json b/packages/with-storybook/tsconfig.json new file mode 100644 index 00000000..c04c6762 --- /dev/null +++ b/packages/with-storybook/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@frontside/tsconfig", + "exclude": ["types/**/*.ts"] +} diff --git a/website/docs/storybook.md b/website/docs/storybook.md index 92736e58..5afba238 100644 --- a/website/docs/storybook.md +++ b/website/docs/storybook.md @@ -3,7 +3,7 @@ id: storybook title: Storybook --- -Interactors not only make writing tests easier, it can also help you develop UI components. With the upcoming release of [`Component Story Format 3.0`](https://storybook.js.org/blog/component-story-format-3-0/), you will be able to use Interactors in [`Storybook`](https://storybook.js.org/). +Interactors not only make writing tests easier, it can also help you develop UI components. Since [`Storybook`](https://storybook.js.org/) 6.4 you will be able to write [`interactive stories`](https://storybook.js.org/blog/interactive-stories-beta/) and use Interactors for them. This requires no additional setup. Just install `@interactors/html` to your project, and then you can use interactors in your stories immediately. @@ -38,6 +38,36 @@ export const FormSignIn = { }; ``` +## Interaction testing + +You can go further and use Interactors to write tests for your stories in Storybook with [interaction testing](https://storybook.js.org/blog/interaction-testing-with-storybook/) feature. + +To use it install `@storybook/addon-interactions` and `@interactors/with-storybook` storybook addons. Add them to your storybook config and enable interactions debugger feature: + +```js +// .storybook/main.js +module.exports = { + addons: ['@storybook/addon-interactions', '@interactors/with-storybook'] + features: { interactionsDebugger: true }, +}; +``` + +Then you are able to extend previous example by adding `Heading('Welcome Homer!').exists()` assertion + + +```js +import { Button, Heading, TextField } from '@interactors/html'; + +export const FormSignIn = { + play: async () => { + await TextField('Email').fillIn('homer@gmail.com'); + await TextField('Password').fillIn('donuts123'); + await Button('Sign In').click(); + await Heading('Welcome Homer!').exists(); + } +}; +``` + ## Up Next On this page we have gone over how Interactors can enhance your experience with Storybook. If you use `Material UI` to design your apps, you will be pleased to know that `Material UI` too can be used with Interactors and Storybook. diff --git a/website/static/img/interactors-logo@4x.png b/website/static/img/interactors-logo@4x.png new file mode 100644 index 00000000..ec956d94 Binary files /dev/null and b/website/static/img/interactors-logo@4x.png differ