[VUE警告]: 运行Jest单元测试时,未知的自定义元素:<nuxt-link>

33

问题

我使用带路由的nuxt 1.4和Jest进行单元测试。我的应用程序没有抛出错误,看起来完美运行。然而,在运行我的单元测试npm run unit(运行jest)时,终端会抛出一个错误:[Vue warn]: Unknown custom element: <nuxt-link> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

期望结果

我期望它不会抛出此错误,因为我的应用程序正在工作。

文件

package.json

{
  "name": "vue-starter",
  "version": "1.0.0",
  "description": "Nuxt.js project",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint",
    "test": "npm run lint && npm run unit",
    "unit": "jest",
    "unit:report": "jest --coverage"
  },
  "dependencies": {
    "babel-jest": "^22.4.1",
    "jest-serializer-vue": "^1.0.0",
    "node-sass": "^4.7.2",
    "npm": "^5.7.1",
    "nuxt": "^1.0.0",
    "sass-loader": "^6.0.7",
    "vue-jest": "^2.1.1"
  },
  "devDependencies": {
    "@vue/test-utils": "^1.0.0-beta.12",
    "babel-eslint": "^8.2.1",
    "eslint": "^4.15.0",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-vue": "^4.0.0",
    "jest": "^22.4.2"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "jest": {
    "moduleFileExtensions": [
      "js",
      "vue"
    ],
    "transform": {
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
      ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
    },
    "snapshotSerializers": [
      "<rootDir>/node_modules/jest-serializer-vue"
    ]
  }
}

我要测试的组件:

<template>
  <div>
    <nuxt-link class="name" :to="{ path: `entity/${item.id}`, params: { id: item.id }}">{{item.name}}</nuxt-link>
    <button class="connect" @click="connect">{{ btnText }}</button>
  </div>
</template>

<script>
  // import nuxtLink from '../.nuxt/components/nuxt-link';

  const connectionStatusMap = [
    'Connect',
    'Connected',
    'Pending',
    'Cancel',
  ];

  export default {
    /*components: {
      'nuxt-link': nuxtLink,
    },*/
    props: {
      item: {
        type: Object
      }
    },
    ...
  }
</script>

我的测试脚本:

import TestItem from '../components/TestItem';
import { shallow, mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import VueRouter from 'vue-router';

const localVue = createLocalVue()

localVue.use(Vuex)
localVue.use(VueRouter)

...
it(`should show the entity`, () => {
    const wrapper = mount(TestItem, {
      propsData: { item },
      localVue,
      store,
      // stubs: ['nuxt-link'],
    })
    expect(wrapper.find('.name').text()).toBe(item.name);
  });

  it(`should show allow me to connect if I'm not yet connected`, () => {
    const wrapper = shallow(TestItem, {
      propsData: { item },
      localVue,
      store,
      stubs: ['nuxt-link'],
    })
    expect(wrapper.find('.connect').text()).toBe('Connect');
  });
  ...

我尝试了

按照这个 Github 评论中的建议,我尝试创建一个 localVue 并对组件进行存根。 我还尝试了shallow/mount,但好像也不起作用。

9个回答

37
这就是我如何成功摆脱烦人的警告的方法: 包含 RouterLinkStub,例如:
包含 RouterLinkStub,例如:
import { shallowMount, createLocalVue, RouterLinkStub } from '@vue/test-utils';

将 NuxtLink 的桩(stub)映射到 RouterLinkStub

const wrapper = shallowMount(TestItem, {
  ...
  stubs: {
    NuxtLink: RouterLinkStub
  }
})

如果您想检查 nuxt-link 文本或其他内容,请更改:

const link = wrapper.find('nuxt-link');

const link = wrapper.find(RouterLinkStub);

https://onigra.github.io/blog/2018/03/19/vue-test-utils-router-link-stub/发现了这个宝藏。

好事是,你不需要懂日语就可以读懂代码...


19

尽管提供的答案可能有效,但我最终使用的是基于这个指南的方法。

const wrapper = mount(TestItem, {
  propsData: { item },
  localVue,
  store,
  stubs: {
    NuxtLink: true,
    // Any other component that you want stubbed
  },
});

4

我使用这个 Storybook 的解决方法,成功让它工作了:

import { mount, createLocalVue } from '@vue/test-utils'
import Component from '@/components/Component.vue'

const localVue = createLocalVue()

localVue.component('nuxt-link', {
  props:   ['to'],
  template: '<a href="#"><slot>NuxtLink</slot></a>',
})

describe('Test Component', () => {

    const wrapper = mount(Component, {
      stubs: ['nuxt-link'],
      localVue
    })
})


4
我添加了下面的代码来使它工作。
  1. 在你的测试文件中
import NuxtLink from "path to nuxt-link.js"

Mycomponent.components.NuxtLink = NuxtLink

在你的Jest配置文件中:
transformIgnorePatterns: [
   "path to nuxt-link.js"
],

或者您可以在挂载选项中添加下面这行代码。
mount(Mycomponent, {stubs: ["nuxt-link"]})

1

我有:

// path: ./test/jest.setup.js

import Vue from 'vue'
import VueTestUtils from '@vue/test-utils'

// Mock Nuxt components
VueTestUtils.config.stubs['nuxt-link'] = '<a><slot /></a>'
VueTestUtils.config.stubs['no-ssr'] = '<span><slot /></span>'

并且

// path: ./jest.config.js

module.exports = {
  // ... other stuff
  setupFilesAfterEnv: ['./test/jest.setup.js']
}

...这解决了我在Nuxt应用程序中所有Jest测试的问题。


1
对于任何遇到“未知自定义元素:<router-link>”问题的人:
我的问题是,在创建组件时我使用了mount而不是shallowshallow用法: 与mount类似,它创建一个Wrapper,其中包含已挂载和呈现的Vue组件,但子组件被存根。 来源: https://vue-test-utils.vuejs.org/en/api/shallow.html 以下是一个可工作的示例:
import { shallow } from '@vue/test-utils';                               
import ContentCard from '../../components/ContentCard.vue';                                                                           
import NuxtLink from '../../.nuxt/components/nuxt-link';                                                                              

const createComponent = propsData => shallow(ContentCard, { propsData });                                                             

describe('ContentCard', () => {                                                                                                       
  let component;                                                                                                                      

  beforeEach(() => {
    ContentCard.components = ContentCard.components || {};                                                                            
    ContentCard.components.NuxtLink = NuxtLink;                                                                                       
  });   

  describe('Properties', () => {
    it('has an imgSrc property', () => {                                                                                              
      component = createComponent({ imgSrc: 'X' });                                                                                   
      expect(component.props().imgSrc).toBe('X');                                                                                     
    });   
  });     
});

现在已将其更名为 shallowMount - MacroMan

1
...
import NuxtLink from '../.nuxt/components/nuxt-link.js'

...
TestItem.components = TestItem.components || {};
TestItem.components.NuxtLink = NuxtLink;
const wrapper = shallow(TestItem, {
    ...
});
...

感谢您的回复。我现在遇到了这个错误 `console.error node_modules/vue/dist/vue.runtime.common.js:589 [Vue warn]: Unknown custom element: <router-link> - did you register the component correctly? For recursive components, make sure to provide the "name" option.(found in )`但是我的应用程序中没有任何router-link元素,只有nuxt-link - Anima-t3d
@Anima-t3d,你找到“router-link”错误的解决方案了吗?我也遇到了完全相同的问题。 - Oldenborg
@Oldenborg,我还没有时间尝试这些解决方案。但很高兴你找到了你的解决方法。 - Anima-t3d

1

Anima-t3d的被接受的答案是有效的,但并不考虑所有用例。

请注意,以下解决方案是针对Nuxt3和vue test-utils v2定制的,因此挂载选项已更改。没有尝试过以前的版本。

用例1:
我不需要访问NuxtLink的内部元素。 => 桩是一个好选择,因此这导致了Anima-t3d的答案:

const wrapper = mount(TestItem, {
  props,
  global: {
    stubs: {
      NuxtLink: true,
    },
  },
});

注意:对于shallowMount,存根需要明确定义。
用例2: 我想出于某些原因访问NuxtLink的内部元素。 => 存根不起作用,而是我们可以在测试文件中定义自定义组件:
wrapper = mount(TestItem, {
  props,
  global: {
    components: {
      NuxtLink: {
        template: '<a><slot/></a>',
      },
    },
  },
});

注意:如果您正在使用 shallowMount,仍然需要在 stubs 中列出 NuxtLink 并将其设置为 false。
wrapper = shallowMount(TestItem, {
  props,
  global: {
    stubs: {
      NuxtLink: false,
    },
    components: {
      NuxtLink: {
        template: '<a><slot/></a>',
      },
    },
  },
});

这个功能是用你定义的模板替换NuxtLink。内部使用的HTML元素保留,属性(如类或“to”属性)会自动应用。

这意味着,给定以下NuxtLink的用法

<NuxtLink
  to="www.example.com"
  class="item-class"
><div>ItemContent</div></NuxtLink>

然后 wrapper.html 的输出将是

<a to="www.example.com" class="item-class"><div>ItemContent</div></a>

0
// test/jestSetup.js

import Vue from 'vue'
import Vuetify from 'vuetify'
import { config } from '@vue/test-utils'

Vue.use(Vuetify)

config.stubs.NuxtLink = { template: '<a><slot /></a>' }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接