vuejs2 - Vue.js 插槽: tags used as slot content - How can I test this?
I have 2 main views which are using a shared layout component which has several named slots. I am passing the slot content through using wrapping <template>
问题描述
I have 2 main views which are using a shared layout component which has several named slots. I am passing the slot content through using wrapping <template>
tags in many cases, as these don't result in unnecessary divs which would break the layouts quite badly. I am trying to write tests to test the two view components.
This works fine but I can't see the content in the output when doing a shallowMount()
to test the component so all of my tests are falling over. Doing a full mount()
isn't a viable solution at all here due to the components being 'page' level and having a lot of side effects (I would be unable to test the interactions that I need to test). I have also tried 'render' as an alternative method but that's no use either as I need to test significant functionality controlling visibility of different components.
This is quite odd behaviour.
Here's part of the receiving layout component...
<template>
<aside :class="`layout-primary__aside ${this.rootClass}__aside`">
<data-container :class="`layout-primary__aside__data ${this.rootClass}__aside__data`">
<slot name="data" />
</data-container>
<slot name="aside" />
<section :class="`layout-primary__cta ${this.rootClass}__cta`">
<slot name="cta" />
</section>
</aside>
</template>
If I pass THIS into the slots (code from one of the view components I am trying to test)...
<template>
<layout root-class="my-view"
title="My View">
<template slot="data">
<data-item label="Total" :value="totalCost" />
</template>
<template slot="aside">
Some random content
</template>
<branded-cta-tile slot="cta"
name="review"
class="cta__tile"
button-text="Review"
:show-back="true"
:breakout-extended="true"
@click="$router.push({ name: 'Review' })"
@back-click="$router.push({ name: 'Chooser' })" />
</template>
Then when I call wrapper.html()
I can see the stubs rendered for the 'branded-cta-tile' but the other elements render simply as <template></template>
<layout-stub rootclass="plan-builder" title="Plan Builder"><template></template> <template></template> <branded-cta-tile-stub name="review" backbuttontext="Back a step" breakoutextended="true" buttontext="Review" showback="true" class="cta__tile"></branded-cta-tile-stub></<layout-stub>
I would EXPECT to see this...
<layout-stub rootclass="plan-builder" title="Plan Builder"><data-item-stub label="Total"></data-item-stub> Some random content <branded-cta-tile-stub name="review" backbuttontext="Back a step" breakoutextended="true" buttontext="Review" showback="true" class="cta__tile"></branded-cta-tile-stub></<layout-stub>
If I change the <template>
tag with a slot name on it to <div>
then it works fine. If I remove the slot name from the <template>
tag then it renders the content inside the tag as you would expect - It seems to fail when you combine the two together.
Is there any workaround for this? If not the only option I realistically have is to duplicate the layout code and markup on 2 different views with what I can see right now.
Add following code in TS file of the component, where you don't want to go back.
@HostListener('window:hashchange', ['$event'])
hashChangeHandler(e) {
window.location.hash = "dontgoback";
}
解决方案
当您调用shallowMount
时,子组件将使用空模板存根,并且只会呈现默认插槽。
您必须提供一个layout
包含命名插槽的模拟来呈现它们。
根据您的问题,我假设 MyComponent 是您正在测试的组件,并且您想断言layout
插槽正在呈现<data-item label="Total" :value="totalCost" />
,Some random content
并且<branded-cta-tile ...>
. 如果不是,请改进您的问题,因为我有点不清楚。例如,您正在测试的视图组件的名称是未知的。我称它们为 MyComponent。
// MyComponent.vue
<template>
<layout root-class="my-view"
title="My View">
<template slot="data">
<data-item label="Total" :value="totalCost" />
</template>
<template slot="aside">
Some random content
</template>
<branded-cta-tile slot="cta"
name="review"
class="cta__tile"
button-text="Review"
:show-back="true"
:breakout-extended="true"
@click="$router.push({ name: 'Review' })"
@back-click="$router.push({ name: 'Chooser' })" />
</template>
// MyComponent.spec.js
import MyComponent from './MyComponent.vue';
import DataItem from './DataItem.vue';
import BrandedCtaTile from './BrandedCtaTile.vue';
shallowMount(MyComponent, {
stubs: {
layout: {
template: `<div>
<slot name="data"></slot>
<slot name="aside"></slot>
<slot name="cta"></slot>
</div>'
}, // Use a mock that renders named slots
DataItem, // Use the real component if you also want to render this component
BrandedCtaTile // Idem
}
});
它将用存根替换布局组件,存根是 SUT 中唯一的组件。如果你不这样做,布局组件将不会呈现命名槽,shallowMount
只会呈现layout
组件的默认槽(= 无)。
推荐阅读
- java - 调用容器“xxxxxx”时出错:在 Redhat Business Central 上解组输入时出错
- quarkus - Quarkus 休眠验证异常未显示在控制台上
- android - 在设置菜单项的可见性时如何解决这个空指针异常?
- python - 在 Tkinter 中切换窗口时,Python-Listbox 项目不会终止
- android - 当我们有 ViewModels 时,我们还需要 onSaveInstanceState() 吗?
- c++ - 'char **':dynamic_cast 的目标类型无效
- gcc - GCC 上 x86 intel asm 中方括号前的偏移量
- mysql - 我的 SQL 数据库不一致(基数与自动增量)
- java - 如何在 sublime text 3 中为 java 构建系统,它也支持包?
- c# - EF Core - 如何在包含的集合中包含项目的集合
I have 2 main views which are using a shared layout component which has several named slots. I am passing the slot content through using wrapping <template>
问题描述
I have 2 main views which are using a shared layout component which has several named slots. I am passing the slot content through using wrapping <template>
tags in many cases, as these don't result in unnecessary divs which would break the layouts quite badly. I am trying to write tests to test the two view components.
This works fine but I can't see the content in the output when doing a shallowMount()
to test the component so all of my tests are falling over. Doing a full mount()
isn't a viable solution at all here due to the components being 'page' level and having a lot of side effects (I would be unable to test the interactions that I need to test). I have also tried 'render' as an alternative method but that's no use either as I need to test significant functionality controlling visibility of different components.
This is quite odd behaviour.
Here's part of the receiving layout component...
<template>
<aside :class="`layout-primary__aside ${this.rootClass}__aside`">
<data-container :class="`layout-primary__aside__data ${this.rootClass}__aside__data`">
<slot name="data" />
</data-container>
<slot name="aside" />
<section :class="`layout-primary__cta ${this.rootClass}__cta`">
<slot name="cta" />
</section>
</aside>
</template>
If I pass THIS into the slots (code from one of the view components I am trying to test)...
<template>
<layout root-class="my-view"
title="My View">
<template slot="data">
<data-item label="Total" :value="totalCost" />
</template>
<template slot="aside">
Some random content
</template>
<branded-cta-tile slot="cta"
name="review"
class="cta__tile"
button-text="Review"
:show-back="true"
:breakout-extended="true"
@click="$router.push({ name: 'Review' })"
@back-click="$router.push({ name: 'Chooser' })" />
</template>
Then when I call wrapper.html()
I can see the stubs rendered for the 'branded-cta-tile' but the other elements render simply as <template></template>
<layout-stub rootclass="plan-builder" title="Plan Builder"><template></template> <template></template> <branded-cta-tile-stub name="review" backbuttontext="Back a step" breakoutextended="true" buttontext="Review" showback="true" class="cta__tile"></branded-cta-tile-stub></<layout-stub>
I would EXPECT to see this...
<layout-stub rootclass="plan-builder" title="Plan Builder"><data-item-stub label="Total"></data-item-stub> Some random content <branded-cta-tile-stub name="review" backbuttontext="Back a step" breakoutextended="true" buttontext="Review" showback="true" class="cta__tile"></branded-cta-tile-stub></<layout-stub>
If I change the <template>
tag with a slot name on it to <div>
then it works fine. If I remove the slot name from the <template>
tag then it renders the content inside the tag as you would expect - It seems to fail when you combine the two together.
Is there any workaround for this? If not the only option I realistically have is to duplicate the layout code and markup on 2 different views with what I can see right now.
Add following code in TS file of the component, where you don't want to go back.
@HostListener('window:hashchange', ['$event'])
hashChangeHandler(e) {
window.location.hash = "dontgoback";
}
当您调用shallowMount
时,子组件将使用空模板存根,并且只会呈现默认插槽。
您必须提供一个layout
包含命名插槽的模拟来呈现它们。
根据您的问题,我假设 MyComponent 是您正在测试的组件,并且您想断言layout
插槽正在呈现<data-item label="Total" :value="totalCost" />
,Some random content
并且<branded-cta-tile ...>
. 如果不是,请改进您的问题,因为我有点不清楚。例如,您正在测试的视图组件的名称是未知的。我称它们为 MyComponent。
// MyComponent.vue
<template>
<layout root-class="my-view"
title="My View">
<template slot="data">
<data-item label="Total" :value="totalCost" />
</template>
<template slot="aside">
Some random content
</template>
<branded-cta-tile slot="cta"
name="review"
class="cta__tile"
button-text="Review"
:show-back="true"
:breakout-extended="true"
@click="$router.push({ name: 'Review' })"
@back-click="$router.push({ name: 'Chooser' })" />
</template>
// MyComponent.spec.js
import MyComponent from './MyComponent.vue';
import DataItem from './DataItem.vue';
import BrandedCtaTile from './BrandedCtaTile.vue';
shallowMount(MyComponent, {
stubs: {
layout: {
template: `<div>
<slot name="data"></slot>
<slot name="aside"></slot>
<slot name="cta"></slot>
</div>'
}, // Use a mock that renders named slots
DataItem, // Use the real component if you also want to render this component
BrandedCtaTile // Idem
}
});
它将用存根替换布局组件,存根是 SUT 中唯一的组件。如果你不这样做,布局组件将不会呈现命名槽,shallowMount
只会呈现layout
组件的默认槽(= 无)。