Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addon-docs: Support CSF3 play function #15511

Open
2 tasks
shilman opened this issue Jul 7, 2021 · 21 comments
Open
2 tasks

Addon-docs: Support CSF3 play function #15511

shilman opened this issue Jul 7, 2021 · 21 comments

Comments

@shilman
Copy link
Member

shilman commented Jul 7, 2021

As a user, I'd like to see stories that use play functions to achieve interactions the same on the Docs page as how it appears on the Storybook Canvas.

Storybook CSF3 adds a play function for scripted interaction with components after a story has rendered. This currently does not work in the docs tab. We need to make it work:

  • For iframe stories
  • For inline stories

There are a few different issues to deal with around dueling play functions and dueling focus.

Dueling play functions

Two play functions can't run at the same time: their events will clobber one another, especially if they require focus, e.g. keyboard events.

One way to deal with this is to run play functions sequentially. This can be problematic for long-running play functions.

Another way to deal with it is to not run play functions on the Docs page at all, and have UI by which the user can run a play function.

Dueling focus

A related issue is dueling Focus. Even if a play function finishes instantaneously, if story A shows element A focused, and story B shows element B focused, then at most one of those stories can show correctly on the Docs page.

The sequential approach above won't fix this. Only the play function UI, would work for this.

Proposal

Since the play function UI works for all cases, that's a relatively simple solution.

Alternative

A more complex solution would be to make it configurable with a parameter, e.g.

parameters: {
  docs: {
    playFunction: true,
  }
}

And then sequentially play all stories with playFunction true. This way the CSF author has control and can set playFunction to false for long-running stories.

┆Issue is synchronized with this Asana task by Unito

@yannbf
Copy link
Member

yannbf commented Jul 15, 2021

Question: How would the following code work in a docs page?

const HelloStory = {
  play: async () => {
    userEvent.type(screen.getByRole('textbox'), 'Hello, World!')
  }
}

const GoodbyeStory = {
  play: async () => {
    userEvent.type(screen.getByRole('textbox'), 'Goodbye, World!')
  }
}

I think getByRole might return an error like: TestingLibraryElementError: Found multiple elements with the role "textbox" because the stories are inline, thus the selectors are duplicated.

@ndelangen
Copy link
Member

@yannbf If the expectation is role='textbox' occurs only once on a screen, then there's no way to work if it appears multiple time.

I only see 2 ways of dealing with this:

  • modify rendering by rendering into an iframe; keep screen implementation as-is
  • keep rendering as-is; modify screen to select within the "targetContainer"

@donaldpipowitch
Copy link
Contributor

donaldpipowitch commented Jul 23, 2021

modify screen to select within the "targetContainer"

Can't we do something similar to the renderResult you get back when Testing Lib takes care of the rendering? It creates some preconfigured queries which are limited to the "targetContainer". Something like that could be passed to the play function?

// how it can be done inside a unit test
import { render } from '@testing-library/react';
const result = render(<GoodbyeStory />);

// in your story (`result` being something similar to what we would get from `render`)
const GoodbyeStory = {
  play: async ({ result }) => {
    userEvent.type(result.getByRole('textbox'), 'Goodbye, World!')
  }
}

Or if you want less coupling to Testing Lib this would be an alternative with a bit more typing:

import { within } from '@testing-library/react';

const GoodbyeStory = {
  play: async ({ container }) => {
    const queries = within(container); // container is just the DOM element with our rendered story
    userEvent.type(queries.getByRole('textbox'), 'Goodbye, World!')
  }
}

@ndelangen
Copy link
Member

const queries = within(container)

❤️

@ndelangen
Copy link
Member

@ghengeveld We talked about this a lot last week, should this ticket be assigned to you or us both perhaps?

@ndelangen
Copy link
Member

@ghengeveld Want to talk about this later this week?

@bodograumann
Copy link
Contributor

Pitty that this is not in 6.4 already, but given that chromatic does not look at the docs page it’s not that bad.

Having play UI on each story with a play function in the docs page sounds great functionally, but is probably not easy to make look good, especially when the story is not wrapped in a Canvas.

Good job with the docs promoting const canvas = within(canvasElement) as standard practice. :-)

Due to the way the interactive step-by-step debugger works, each play function instruction already has to be written in a way that is independant from the current state of focus. Is this something you want to tackle there as well?

@stale
Copy link

stale bot commented Jan 9, 2022

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

@stale stale bot added the inactive label Jan 9, 2022
@bodograumann
Copy link
Contributor

I feel like issue, where someone is assigned, shouldn't be closed automatically.

@stale stale bot removed the inactive label Jan 10, 2022
@bodograumann
Copy link
Contributor

Is this included in version 6.5?

@shilman
Copy link
Member Author

shilman commented May 10, 2022

@bodograumann nope, unfortunately not. 7.0 🤞

@ndelangen ndelangen removed their assignment Jul 1, 2022
@shilman shilman removed the P0 label Oct 18, 2022
@cazdev
Copy link

cazdev commented Mar 10, 2023

Is this included in 7.0?

@yannbf
Copy link
Member

yannbf commented Apr 21, 2023

Is this included in 7.0?

Great question! Yes, the play function works in MDX, however does not run by defualt. You can try it out with the Story block by passing the autoplay property to it, and then it will:

import { Meta, Story } from '@storybook/blocks'
import * as ButtonStories from './Button.stories'

# Button

<Meta of={ButtonStories} />
<Story of={ButtonStories.Primary} autoplay />

@ignaciolarranaga
Copy link

Is there a way to run it on the default template @yannbf ?

@yannbf
Copy link
Member

yannbf commented Apr 23, 2023

Is there a way to run it on the default template @yannbf ?

Good question! I don't think so? @JReinhold @tmeasday could answer this one.

I was going to suggest to write a custom default autodocs template but you'd end up using the <Stories /> block and not the <Story /> one. The Stories block does not (currently) have an autoplay prop that would be passed down to all stories.

@JReinhold
Copy link
Contributor

JReinhold commented Apr 23, 2023

Is there a way to run it on the default template @yannbf ?

There is! All props on doc blocks can also be set via parameters on stories/component/project. So you can set parameters.docs.story.autoplay = true, documented here: https://storybook.js.org/docs/react/api/doc-block-story#autoplay

@jonniebigodes
Copy link
Contributor

jonniebigodes commented Apr 23, 2023

@ignaciolarranaga we have documentation on this. If you check this, you'll see all the available props and what is available with that Doc Block. Heads up, @JReinhold, check your link. You referenced something unrelated to the conversation. Might I suggest that you remove it?

@shilman shilman removed the todo label Jun 20, 2023
@Leland
Copy link

Leland commented Nov 8, 2023

After searching far and wide and finally finding this thread, it's worth pointing out that previous versions' documentation does not indicate that play functions will not be ran on DocsPages: https://storybook.js.org/docs/6.5/react/writing-stories/play-function#writing-stories-with-the-play-function

The inclusion of MDX files on this v6.5 documentation even may make it seem that it's allowed, as does this generic language:

Play functions are small snippets of code executed after the story renders

@yannbf
Copy link
Member

yannbf commented Dec 1, 2023

cc @jonniebigodes ☝️

@donaldpipowitch
Copy link
Contributor

Is it possible to run play functions in the docs page with some workaround today? I tried setting parameters.docs.story.autoplay = true in my preview.tsx, but it doesn't seem to have an effect.

@JReinhold
Copy link
Contributor

Is it possible to run play functions in the docs page with some workaround today? I tried setting parameters.docs.story.autoplay = true in my preview.tsx, but it doesn't seem to have an effect.

@donaldpipowitch that should be the current workaround, so if that doesn't work, that's a bug. Can you open a separate bug report with a minimal reproduction?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests