Storybook: 【Help Wanted】Failed to mount Vue component error

Created on 30 Oct 2018  ·  8Comments  ·  Source: storybookjs/storybook

Bug or support request summary

Custom components registered to stories are not mounted when running storyshots.

console.error node_modules/vue/dist/vue.esm.js 591
  [Vue warn]: Failed to mount component: template or render function not defined.

  found in

  ---> <Pager>
             <Root>

I pretty much followed every steps displayed on the example.

Package versions:

  • "@storybook/vue": "4.0.0"
  • "@storybook/addon-storyshots": "4.0.0"
  • "jest-vue-preprocessor": "^1.4.0"
  • "jest-serializer-vue": "^2.0.2"
  • "typescript": "^3.1.3"
  • "vue-loader": "^15.4.2"
  • "vue": "^2.5.17"
// package.json
...
{
  "scripts": {
    "snapshot": "jest --config=jest.config.snapshot.js",
    ...
  }
}
// jest.config.snapshot.js
module.exports = {
  moduleFileExtensions: ['vue', 'js', 'ts', 'json'],
  moduleDirectories: ['node_modules'],
  transform: {
    '^.+\\.js$': 'ts-jest',
    '^.+\\.ts$': 'ts-jest',
    '.*\\.(vue)$': '<rootDir>/node_modules/jest-vue-preprocessor'
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
    '[^/]vue$': 'vue/dist/vue.esm.js',
    '^@storybook/(.*)$': '<rootDir>/node_modules/@storybook/$1'
  },
  snapshotSerializers: ['jest-serializer-vue'],
  testMatch: ['<rootDir>/test/snapshot/*.js'],
  verbose: true,
  setupFiles: ['<rootDir>/.jest/register-context.js'],
  transformIgnorePatterns: [
    './node_modules/(?!vue)',
    './node_modules/@storybook'
  ],
  globals: {
    'ts-jest': {
      babelConfig: '.babelrc'
    }
  }
}
// .jest/register-context.js
import registerRequireContextHook from 'babel-plugin-require-context-hook/register'
registerRequireContextHook()
// Pager.vue
<template>
  <div class="Pager">
    <button
      :disabled="internalCurrentPage === 1"
      class="Pager__ArrowButton"
      @click="onClickPrev"
    >←</button>
    <button
      :disabled="internalCurrentPage === maxPage"
      class="Pager__ArrowButton"
      @click="onClickNext"
    >→</button>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

interface IData {
  internalCurrentPage: number
}

export default Vue.extend({
  props: {
    currentPage: {
      type: Number,
      default: 1
    },
    size: {
      type: Number,
      default: 1
    },
    total: {
      type: Number,
      default: 20
    }
  },
  data(): IData {
    return {
      internalCurrentPage: 1
    }
  },
  computed: {
    maxPage(): number {
      return Math.ceil(this.total / this.size)
    }
  },
  watch: {
    currentPage: {
      immediate: true,
      handler(val) {
        this.internalCurrentPage = val
      }
    }
  },
  methods: {
    onClickNumButton(pageNum: number) {
      this.internalCurrentPage = pageNum
      this.$emit('change', this.internalCurrentPage)
    },
    onClickPrev() {
      this.internalCurrentPage -= 1
      this.$emit('change', this.internalCurrentPage)
    },
    onClickNext() {
      this.internalCurrentPage += 1
      this.$emit('change', this.internalCurrentPage)
    }
  }
})
</script>

<style scoped>
...
</style>
// Pager.story.ts
import { storiesOf } from '@storybook/vue'

import Pager from './Pager.vue'

storiesOf('components/Base/Pager', module).add('Default', () => ({
  components: { Pager },
  data() {
    return {
      currentPage: 1
    }
  },
  template: `
    <div class="Storybook">
      <div class="StorybookSection">
        <div class="StorybookSection__Header">Pager</div>
        <div class="StorybookSection__Body dark">
          <div class="wrapper" style="width: 100%">
            <div style="color: #fff;margin-bottom: 16px;font-size: 18px;font-weight: bold;">Current Page: {{ currentPage }}</div>
            <Pager :currentPage="currentPage" :size="1" :total="10" @change="num => currentPage = num" />
          </div>
        </div>
      </div>
    </div>
  `
}))

Storybook

Yes, everything is working on Storybook.

2018-10-30 23 34 50

It breaks only when running on Jest.

Looking forward any advice could fix my issue.Thanks

storyshots vue question / support

All 8 comments

I can't point to something specific in your setup. Having a reproduction will be much helpful

I've pushed a dedicated branch to reproduce the problem in my repo.
https://github.com/andoshin11/spa-playground/tree/fix/storyshots-error

Running $ yarn run snapshot will give you the error shown above.

I've tried to figure it out what's going on, but without progress. Will try to debug a bit later.

Thanks a lot for your kindness, Igor

I've managed to make it work without typescript.

Thise error:

[Vue warn]: Failed to mount component: template or render function not defined.

means we can't use dist/vue.common, because it's bundled without compiler, and we need compile to compile templats =/

If I remove this mapping, I am getting a TS error that seems to be similar to this - https://github.com/vuejs/vue-hot-reload-api/issues/61

Will continue to dig in it

Actually, we are mocking vue to use vue.common inside the storyshots. So probably ☝️ is not 100% accurate

Got it working with a bit different approach.

First of all, I can confirm that the problem is with vue/jest/typescript . So probably there is a different solution by changing something in tsconfig.

Currently, the vue-jest-preprocessor is using typescript compiler when the lang="ts" is defined in the

Related issues

tirli picture tirli  ·  3Comments

ZigGreen picture ZigGreen  ·  3Comments

sakulstra picture sakulstra  ·  3Comments

shilman picture shilman  ·  3Comments

miljan-aleksic picture miljan-aleksic  ·  3Comments