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

Question/Possible Feature Request: Screenshots of different variants/args? #81

Open
BCerki opened this issue Oct 26, 2022 · 4 comments
Open

Comments

@BCerki
Copy link

BCerki commented Oct 26, 2022

Good afternoon! Thanks so much for creating this plugin—it's a very helpful tool.

We're building a component library with Storybook and using the plugin to take screenshots of all of our components for visual testing in CI. Instead of creating a story for each variant, we allow users to explore the different colours, sizes, arguments, etc. with the Storybook Controls add-on. Is there a way to configure the plugin so it takes multiple screenshots of the same story with different arguments?

In case it's helpful, here's an example of our Button component story. (Our component library is all about progressive enhancement, so our stories showcase that while other options are available via the Controls.)

I've looked into the variants add on, but it would require making an All Variants story and/or adding code to each story individually, which isn't quite what we're trying to do.

Please let me know if you'd like more details, or if I can further help.

Thanks so much!

@trotzig
Copy link
Contributor

trotzig commented Oct 27, 2022

Hi @BCerki! Good question! The short answer is no, Happo takes only one screenshot per variant. There is the interactions add-on that allow you to interact with the UI as part of rendering a story, but that only runs once per story so it's not really an option here.

With the boring answer out of the way, let's see if we can figure out ideas on how to get this solved. My first thought was that we can somehow extract information from the Controls add-on and auto-generate variants from it. But I quickly realized this would lead to an exponential number of variants. For instance, the TextArea component has 8 props that can be configured. Auto-generating all possible combinations would result in ... a whole lot of variants. So we need to curate a set of variants to feed into Happo. The easiest way of doing that would be to simply add them as exported variants in the code, e.g.

// TextArea.stories.tsx

// The first two are the ones we normally have
export const Default = Template.bind({});
Default.args = args;

export const HTML = HTMLTemplate.bind({});
HTML.args = args;


// Then we specify special variants for Happo
export const Disabled = () => <Textarea {...args} disabled />;
export const SmallDisabled = () => <Textarea {...args} disabled size="small" />;

Of course this would also mean that the new Happo variants would show up in the regular Storybook UI, which might not be what we want. We could solve this by conditionally hiding Happo variants if they are not in a Happo environment. I'm not 100% sure how we do this since exports are static and can't be conditionally added. Maybe if we prefixed everything with "Happo" we could write a babel plugin that would strip out anything matching `/^Happo.*/?

// TextArea.stories.tsx
export const HappoDisabled = () => <Textarea {...args} disabled />;
export const HappoSmallDisabled = () => <Textarea {...args} disabled size="small" />;

The plugin could look something like this:

module.exports = () => ({
  name: 'babel-plugin-remove-happo-exports',
  visitor: {
    ExportNamedDeclaration: (path, { opts }) => {
      if (path.node.declaration.declarations[0].id.name.startsWith('Happo')) {
        path.remove();
      }   
    }
  }
});

I've tested this via a babel playground and it works, at least for a very simple case.

We can then adjust the babel plugin to not remove the exports if it's for a Happo run using an environment variable:

const { REMOVE_HAPPO_EXPORTS } = process.env;
module.exports = () => ({
  name: 'babel-plugin-remove-happo-exports',
  visitor: {
    ExportNamedDeclaration: (path, { opts }) => {
      if (REMOVE_HAPPO_EXPORTS !== 'false' && path.node.declaration.declarations[0].id.name.startsWith('Happo')) {
        path.remove();
      }   
    }
  }
});

And then when invoking the Happo run, we inject the environment variable:

REMOVE_HAPPO_EXPORTS=false yarn happo-ci-github-actions

Let me know what you think of this idea!

@BCerki
Copy link
Author

BCerki commented Oct 27, 2022

Thanks for such a thoughtful response! These suggestions look great. I'll experiment with them and post an update later this week.

@trotzig
Copy link
Contributor

trotzig commented Oct 27, 2022

Excellent! I forgot to mention I did some exploratory work myself on a fork of service-development-toolkit. The babel plugin works but it looks like Storybook chokes when the export is stripped out. The following error appears when we've stripped out some exports from Button.stories.tsx:

Unexpected error while loading ./Button.stories.tsx: ReferenceError: HappoDisabled is not defined

I believe this is coming from @storybook/source-loader. There's a separate process (outside of the webpack build) parsing the stories files for exports. We'll likely have to inject ourselves here too. Not sure how to do that though. 🤔

Here's a link to the commit on my fork where I was exploring this: trotzig/service-development-toolkit@d8f86db

@BCerki
Copy link
Author

BCerki commented Oct 27, 2022

Just a short update for now: Storybook is considering a feature to hide stories that might do the job

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

No branches or pull requests

2 participants