Vue.js 过滤器和测试
Vue.js filters and testing
我使用 vue-cli 创建示例项目 vue init webpack my-test3
,并选择包括 e2e 和单元测试。
问题 1: 根据 template filters 的文档,我尝试在 main.js
中添加新过滤器:
import Vue from 'vue'
import App from './App'
/* eslint-disable no-new */
new Vue({
el: '#app',
template: '<App/>',
components: { App },
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
})
还有我的 App.vue
:
<template>
<div id="app">
<img src="./assets/logo.png">
<hello></hello>
<world></world>
<div class="test-test">{{ 'tesT' | capitalize }}</div>
</div>
</template>
<script>
import Hello from './components/Hello'
import World from './components/World'
export default {
name: 'app',
components: {
Hello,
World
}
}
</script>
我收到警告(错误):
[Vue warn]: Failed to resolve filter: capitalize (found in component <app>)
如果我在初始化新的 Vue 应用程序之前修改 main.js
以注册过滤器,那么它可以正常工作。
import Vue from 'vue'
import App from './App'
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
/* eslint-disable no-new */
new Vue({
el: '#app',
template: '<App/>',
components: { App }
})
为什么一个有效而另一个无效?
问题 2: 上面的示例有效 Vue.filter(...
,我为 World.vue
组件添加了一个测试:
<template>
<div class="world">
<h1>{{ msg | capitalize }}</h1>
<h2>{{ desc }}</h2>
Items (<span>{{ items.length }}</span>)
<ul v-for="item in items">
<li>{{ item }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'world',
data () {
return {
msg: 'worldly App',
desc: 'This is world description.',
items: [ 'Mon', 'Wed', 'Fri', 'Sun' ]
}
}
}
</script>
和World.spec.js
:
import Vue from 'vue'
import World from 'src/components/World'
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
describe('World.vue', () => {
it('should render correct title', () => {
const vm = new Vue({
el: document.createElement('div'),
render: (h) => h(World)
})
expect(vm.$el.querySelector('.world h1').textContent)
.to.equal('Worldly App')
})
it('should render correct description', () => {
const vm = new Vue({
el: document.createElement('div'),
render: (w) => w(World)
})
expect(vm.$el.querySelector('.world h2').textContent)
.to.equal('This is world description.')
})
})
为了通过上述测试,我需要包含 Vue.filter(...
过滤器大写的定义,否则测试会失败。所以我的问题是,如何构造 filters/components 并初始化它们,以便测试更容易?
我觉得我不应该在单元测试中注册过滤器,那应该是组件初始化的一部分。但是,如果组件是从主应用程序定义的 inheriting/using 过滤器,则测试组件将不起作用。
有什么建议、意见、阅读材料吗?
我最好的猜测是,如果您在组件内定义 filters
,它们将只能在该组件内使用。在您的情况下,您只能在主 Vue 实例中使用 capitalize
,而不能在其子组件中使用。将其移至全球级别即可解决问题。
对于第二个问题,您在测试文件中添加过滤器定义是正确的。
一个好的做法是创建一个过滤器文件夹,并在该文件夹内的各个文件中定义您的过滤器,如果您想在所有组件中访问它们,则全局定义所有过滤器,例如:
// capitalize.js
export default function capitalize(value) {
if (!value) return '';
value = value.toString().toLowerCase();
value = /\.\s/.test(value) ? value.split('. ') : [value];
value.forEach((part, index) => {
let firstLetter = 0;
part = part.trim();
firstLetter = part.split('').findIndex(letter => /[a-zA-Z]/.test(letter));
value[index] = part.split('');
value[index][firstLetter] = value[index][firstLetter].toUpperCase();
value[index] = value[index].join('');
});
return value.join('. ').trim();
}
要成功测试它,如果您使用 @vue/test-utils 来测试您的单个文件组件,您可以使用 createLocalVue
来测试它,如下所示:
// your-component.spec.js
import { createLocalVue, shallowMount } from '@vue/test-utils';
import capitalize from '../path/to/your/filter/capitalize.js';
import YOUR_COMPONENT from '../path/to/your/component.vue';
describe('Describe YOUR_COMPONENT component', () => {
const localVue = createLocalVue();
// this is the key line
localVue.filter('capitalize', capitalize);
const wrapper = shallowMount(YOUR_COMPONENT, {
// here you can define the required data and mocks
localVue,
propsData: {
yourProp: 'value of your prop',
},
mocks: {
// here you can define all your mocks
// like translate function and others.
},
});
it('passes the sanity check and creates a wrapper', () => {
expect(wrapper.isVueInstance()).toBe(true);
});
});
希望能帮到你
此致。
我使用 vue-cli 创建示例项目 vue init webpack my-test3
,并选择包括 e2e 和单元测试。
问题 1: 根据 template filters 的文档,我尝试在 main.js
中添加新过滤器:
import Vue from 'vue'
import App from './App'
/* eslint-disable no-new */
new Vue({
el: '#app',
template: '<App/>',
components: { App },
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
})
还有我的 App.vue
:
<template>
<div id="app">
<img src="./assets/logo.png">
<hello></hello>
<world></world>
<div class="test-test">{{ 'tesT' | capitalize }}</div>
</div>
</template>
<script>
import Hello from './components/Hello'
import World from './components/World'
export default {
name: 'app',
components: {
Hello,
World
}
}
</script>
我收到警告(错误):
[Vue warn]: Failed to resolve filter: capitalize (found in component <app>)
如果我在初始化新的 Vue 应用程序之前修改 main.js
以注册过滤器,那么它可以正常工作。
import Vue from 'vue'
import App from './App'
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
/* eslint-disable no-new */
new Vue({
el: '#app',
template: '<App/>',
components: { App }
})
为什么一个有效而另一个无效?
问题 2: 上面的示例有效 Vue.filter(...
,我为 World.vue
组件添加了一个测试:
<template>
<div class="world">
<h1>{{ msg | capitalize }}</h1>
<h2>{{ desc }}</h2>
Items (<span>{{ items.length }}</span>)
<ul v-for="item in items">
<li>{{ item }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'world',
data () {
return {
msg: 'worldly App',
desc: 'This is world description.',
items: [ 'Mon', 'Wed', 'Fri', 'Sun' ]
}
}
}
</script>
和World.spec.js
:
import Vue from 'vue'
import World from 'src/components/World'
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
describe('World.vue', () => {
it('should render correct title', () => {
const vm = new Vue({
el: document.createElement('div'),
render: (h) => h(World)
})
expect(vm.$el.querySelector('.world h1').textContent)
.to.equal('Worldly App')
})
it('should render correct description', () => {
const vm = new Vue({
el: document.createElement('div'),
render: (w) => w(World)
})
expect(vm.$el.querySelector('.world h2').textContent)
.to.equal('This is world description.')
})
})
为了通过上述测试,我需要包含 Vue.filter(...
过滤器大写的定义,否则测试会失败。所以我的问题是,如何构造 filters/components 并初始化它们,以便测试更容易?
我觉得我不应该在单元测试中注册过滤器,那应该是组件初始化的一部分。但是,如果组件是从主应用程序定义的 inheriting/using 过滤器,则测试组件将不起作用。
有什么建议、意见、阅读材料吗?
我最好的猜测是,如果您在组件内定义 filters
,它们将只能在该组件内使用。在您的情况下,您只能在主 Vue 实例中使用 capitalize
,而不能在其子组件中使用。将其移至全球级别即可解决问题。
对于第二个问题,您在测试文件中添加过滤器定义是正确的。
一个好的做法是创建一个过滤器文件夹,并在该文件夹内的各个文件中定义您的过滤器,如果您想在所有组件中访问它们,则全局定义所有过滤器,例如:
// capitalize.js
export default function capitalize(value) {
if (!value) return '';
value = value.toString().toLowerCase();
value = /\.\s/.test(value) ? value.split('. ') : [value];
value.forEach((part, index) => {
let firstLetter = 0;
part = part.trim();
firstLetter = part.split('').findIndex(letter => /[a-zA-Z]/.test(letter));
value[index] = part.split('');
value[index][firstLetter] = value[index][firstLetter].toUpperCase();
value[index] = value[index].join('');
});
return value.join('. ').trim();
}
要成功测试它,如果您使用 @vue/test-utils 来测试您的单个文件组件,您可以使用 createLocalVue
来测试它,如下所示:
// your-component.spec.js
import { createLocalVue, shallowMount } from '@vue/test-utils';
import capitalize from '../path/to/your/filter/capitalize.js';
import YOUR_COMPONENT from '../path/to/your/component.vue';
describe('Describe YOUR_COMPONENT component', () => {
const localVue = createLocalVue();
// this is the key line
localVue.filter('capitalize', capitalize);
const wrapper = shallowMount(YOUR_COMPONENT, {
// here you can define the required data and mocks
localVue,
propsData: {
yourProp: 'value of your prop',
},
mocks: {
// here you can define all your mocks
// like translate function and others.
},
});
it('passes the sanity check and creates a wrapper', () => {
expect(wrapper.isVueInstance()).toBe(true);
});
});
希望能帮到你
此致。