storybook: argTypes mapping doesn't work with Vue props

Describe the bug When using the new mapping feature for an argType that corresponds to a prop of a Vue component, the mapping is applied to the value that is passed to args, but is not applied to the value of the prop that is passed to the component.

To Reproduce Steps to reproduce the behavior:

  1. Create a story for a Vue component, with automatic prop detection (using the docs addon)
  2. For one of the props, add an entry to the story’s argTypes that includes options and mapping keys
  3. Open the story in the browser, and change the value of this prop back and forth

Expected behavior The mapping should be applied to the value of the prop, but it’s not.

Code snippets

import MyButton from './Button.vue`;
import Vue from 'vue';
import { Args, StoryContext } from '@storybook/addons';

export default {
	title: 'Components/Button',
	component: MyButton,
	argTypes: {
		label: {
			options: [ 'short', 'medium', 'long' ],
			mapping: {
				short: 'Short',
				medium: 'Medium text',
				long: 'Very long text that is meant to demonstrate how the button wraps text'
			},
			defaultValue: 'short',
			control: 'inline-radio'
		}
	}
};

export const SimpleStory = ( _args: Args, { argTypes } : StoryContext ) : Vue.Component =>
	Vue.extend( {
		components: { MyButton },
		props: Object.keys( argTypes ),
		template: `<my-button v-bind="$props" />`
	} );

With this snippet, I expect the label of the button to change between Short, Medium text and Very long text that... (the mapped values) when the user clicks the radio buttons in the controls panel. Instead, the label of the button changes between short, medium and long (the unmapped values).

Interestingly, if you put console.log( _args.label ) somewhere (either in the arrow function above Vue.extend, or in a mounted lifecycle hook), it prints Short, indicating that the values in _args are mapped correctly. That mapping just isn’t applied to the props that are passed to the Vue component.

(I’m using Vue 2 here, I haven’t tested this with Vue 3.)

System

$ npx sb@next info

Environment Info:

  System:
    OS: Linux 5.4 Ubuntu 20.04.2 LTS (Focal Fossa)
    CPU: (8) x64 Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
  Binaries:
    Node: 14.16.0 - ~/.nvm/versions/node/v14.16.0/bin/node
    npm: 7.6.0 - ~/.nvm/versions/node/v14.16.0/bin/npm
  Browsers:
    Chrome: 89.0.4389.90
    Firefox: 87.0
  npmPackages:
    @storybook/addon-a11y: 6.2.1 => 6.2.1 
    @storybook/addon-actions: 6.2.1 => 6.2.1 
    @storybook/addon-backgrounds: 6.2.1 => 6.2.1 
    @storybook/addon-controls: 6.2.1 => 6.2.1 
    @storybook/addon-docs: 6.2.1 => 6.2.1 
    @storybook/addon-links: 6.2.1 => 6.2.1 
    @storybook/addon-storysource: 6.2.1 => 6.2.1 
    @storybook/addon-viewport: 6.2.1 => 6.2.1 
    @storybook/vue: 6.2.1 => 6.2.1 

┆Issue is synchronized with this Asana task by Unito

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 11
  • Comments: 19 (6 by maintainers)

Most upvoted comments

This issue is still active.

Can confirm that this is still an issue

Facing the same issue

The same happens to me on 6.3.12

const propValues = {prop1, prop2} // prop1 and prop2 are objects

export default {
  title: 'MyTitle',
  argTypes: {
    propToPass: {
      name: 'Prop Name',
      options: Object.keys(propValues),
      mapping: propValues,
      control: {
        type: 'select',
        labels: {
          prop1: 'Label 1',
          prop2: 'Label 2',
        }
      },
    },
 }

then the Storybook throws in console Invalid prop: type check failed for prop "propToPass". Expected Object, got String with value "prop1".

Labels work fine though

@shilman I’m using v6.3.12.

This is what I tried, but instead of the group variable, I only received the string ‘Group’:

export default {
  title: 'Components/Editor',
  component: Editor,
    argTypes: {
      group: {
        options: ['Group'],
        mapping: {
          'Group': group,
        },
      },
    },
  ),
};

I’ve also just run into this with my Vue2 storybook.

On Storybook 7 with Vue 3, argtype mappings work much better: in both canvas and doc modes, clicking a control applies the mapped argtype value. I’m not able to test with Vue 2 any more though.

But not everything works. In both modes, the default value for a mapped argtype is not mapped to the corresponding control, so the control looks like no value is selected. I’m making a separate ticket for this.

I said lots of silly things so let’s go at it again.

Mappings work in the docs renderer. That is because it always rerenders the whole component on control change. They do not work in the canvas renderer.

I have tested on

  • StoryBook 6.4 / Vue 2.6 / Webpack 4 / Vue-Class-Component latest
  • StoryBook 7.0-alpha37 / Vue 2.7 / Vite / Vue-Class-Component latest

In SB7, both canvas and docs share their rendering code and both exhibit the bug. The value is not mapped.

Until this can be fixed, please find an updated MWE workaround:

// Assuming you have MyComponent, and args

const Template = (storyArgs, { argTypes } => {
  return {
    computed: {
      props() {
        const finalProps = { ...this.$props }

        // Reapply mappings to circumvent Storybook Vue 2 bug.
        Object.entries(this.$props)
          .filter(([key, value]) =>
            Object.hasOwn(argTypes[key]?.mapping || {}, value),
          )
          .forEach(([key, value]) => {
            finalProps[key] = argTypes[key].mapping[value]
          })

        return finalProps
      },
    },
    props: Object.keys(argTypes),
    template: `<MyComponent v-bind="props" />`,
  }
}

Template.args = args