storybook icon indicating copy to clipboard operation
storybook copied to clipboard

Trigger Vue event with $event happen `method "toJSON" is not defined` by Addon Action

Open VisionYi opened this issue 3 years ago • 11 comments

Describe the bug When adding the $event props for the event method of Vue component and trigger the event on Storybook button, the Addon Action and Vue will happen the error message below: [Vue warn]: Property or method "toJSON" is not defined on the instance but referenced during render

image bug

To Reproduce

  1. I create an application with the command: npx vue create vue-cli-storybook with vue-router, vuex and eslint. (@vue/cli 4.5.13)
  2. I install the Storybook with the command: npx sb init
  3. Then, I add the $event props on onClick method on the example file ./src/stories/Button.vue like this:
methods: {
  onClick($event) {
    this.$emit('onClick', $event);
  },
},
  1. run storybook npm run storybook and open Addon Actions console to trigger the button event.

The example repository: https://github.com/VisionYi/vue-cli-storybook

System

  • System:
    • OS: macOS 11.1
    • CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
  • Binaries:
    • Node: 14.15.4 - /usr/local/bin/node
    • Yarn: 1.22.10 - /usr/local/bin/yarn
    • npm: 6.14.10 - /usr/local/bin/npm
  • Browsers:
    • Chrome: 90.0.4430.212
    • Firefox: 85.0
    • Safari: 14.0.2
  • npmPackages:
    • @storybook/addon-actions: ^6.2.9 => 6.2.9
    • @storybook/addon-essentials: ^6.2.9 => 6.2.9
    • @storybook/addon-links: ^6.2.9 => 6.2.9
    • @storybook/vue: ^6.2.9 => 6.2.9

Additional context I think it is related to this issue [Addon Action in v5]: Issue when serializing a Vue instance.

In my real project with Storybook v6.1.x that didn't happen like this error, but I upgrade the version to v6.2.9 just have this problem...

In addition, this problem causes severe delay to trigger the event.

VisionYi avatar May 14 '21 10:05 VisionYi

I had the same issue, but for me it is only present when I have v-on="$listeners" on my component. Like this:

<template>
  <button v-on="$listeners">
    <slot />
  </button>
</template>

metal-gogo avatar Jun 16 '21 18:06 metal-gogo

Hi, @shilman Could the Storybook team fix this issue? or any plan to improve that?

VisionYi avatar Jun 23 '21 07:06 VisionYi

@VisionYi does the workaround in #14933 work for you?

shilman avatar Jun 23 '21 08:06 shilman

@shilman I only can replace $event with a clear value as a prop, it can avoid the error message that happened. Avoid Vue event object as the prop to pass to the parent component. But it is not a workaround.

By the way, https://github.com/storybookjs/storybook/issues/14933#issuecomment-862621433 is also not a workaround.

VisionYi avatar Jun 27 '21 12:06 VisionYi

Hi,

I am also experiencing the above issue, the differences being that:

  1. my package version are as follows: "@storybook/addon-actions": "^6.3.0", "@storybook/addon-essentials": "^6.3.0", "@storybook/vue": "^6.3.0"

  2. I am using the actions through the args property on the template: Button.args = { onClick: action('clicked'), }

The result I see is:

  1. an immediate action is printed in the actions panel, containing the event that was emitted from the tested component and accompanied by the console message regarding the "toJSON" method
  2. then a pretty long pause where the browser is frozen
  3. and finally an additional action is displayed in the actions panel.

Please note that that last event contains eventPhase: 3, so I assume it is displayed as a result of the bubbling phase of the event.

Thanks!

reutgrubervcita avatar Jun 28 '21 08:06 reutgrubervcita

I'm also experiencing this issue. I need my vue component to emit the native event because I'm going to be using it in a library. Is there a solution for this?

LawrenceB5477 avatar Jul 19 '21 20:07 LawrenceB5477

I think I figured it out to some extent, though with some limitations.

make sure to have this in your preview.js file export const parameters = { actions: { argTypesRegex: "^on[A-Z].*" }, This will cause storybook to automatically generate action objects for each action that the component dispatches, which matches the above matcher. so this forced me to change the name of my event from "click" to "onClick", because otherwise it did not get picked up.

now my template in the story looks something like this: template: '<Button :label="label" :size="size" :type="type" @onClick="onClick"/>', and I don't define the onClick function anywhere in my file, it is created for me by storybook.

and now when I click my button, I don't get an error and only one action shows up in the actions tab.

I don't like that it forces me to change the event name, but I guess I can live with it, or take the time to play around with the regex.

reutgrubervcita avatar Jul 20 '21 11:07 reutgrubervcita

I found the issue source:

  1. @storybook/addon-actions use the Telejson library to stringify the props ($event) of Vue event and show them on the Actions console.
  2. Telejson stringify the props ($event) by JSON.stringify and do some conversion processes to be an object (?)
  3. JSON.stringify will call property named toJSON. (reference link)
  4. Vue will warn about an undeclared method being referenced during render.
[Vue warn]: Property or method "toJSON" is not defined on the instance but referenced during render

Then, I try below testing: (change $event to this)

// Button.vue
methods: {
  onClick($event) {
    this.$emit('onClick', this);
  },
},

It also will get the same error warning. I think this issue is Telejson caused a puzzling error in Vue.

The workaround is to insert the toJSON method in the Vue instance or component instance, like:

// Button.stories.js
const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { MyButton },
  template: '<my-button @onClick="onClick" v-bind="$props" />',
  methods: { toJSON: () => {} },
});

or Vue top-level prototype, you can put it on .stroybook/preview.js file:

Vue.prototype.toJSON = () => {}

Actually, please put this solution on the Addon Actions Readme.md, because it is a special error case for Vue and depend on the Telejson issue or technical limitations.

VisionYi avatar Sep 16 '21 05:09 VisionYi

@metal-gogo @reutgrubervcita @LawrenceB5477 You can try the workaround above on your project.

VisionYi avatar Sep 16 '21 05:09 VisionYi

Any updates on this issue?

mikemklee avatar Apr 19 '22 00:04 mikemklee

Any updates on this issue?

DiegoLopesLima avatar Sep 13 '22 01:09 DiegoLopesLima