Skip to content

Commit a7fdcbd

Browse files
Chris WaddellJessicaSachs
Chris Waddell
authored andcommitted
enforce consistent sort order of named slots in shallowMount output
1 parent f9783fd commit a7fdcbd

File tree

2 files changed

+43
-28
lines changed

2 files changed

+43
-28
lines changed

packages/create-instance/create-component-stubs.js

+34-23
Original file line numberDiff line numberDiff line change
@@ -110,37 +110,48 @@ export function createStubFromComponent(
110110
// ignoreElements does not exist in Vue 2.0.x
111111
if (Vue.config.ignoredElements) {
112112
Vue.config.ignoredElements.push(tagName)
113+
if (Vue.config.ignoredElements.indexOf('template-stub') === -1) {
114+
Vue.config.ignoredElements.push('template-stub')
115+
}
113116
}
114117

115118
return {
116119
...getCoreProperties(componentOptions),
117120
$_vueTestUtils_original: originalComponent,
118121
$_doNotStubChildren: true,
119122
render(h, context) {
120-
return h(
121-
tagName,
122-
{
123-
ref: componentOptions.functional ? context.data.ref : undefined,
124-
attrs: componentOptions.functional
125-
? {
126-
...context.props,
127-
...context.data.attrs,
128-
class: createClassString(
129-
context.data.staticClass,
130-
context.data.class
131-
)
132-
}
133-
: {
134-
...this.$props
135-
}
136-
},
137-
context
138-
? context.children
139-
: this.$options._renderChildren ||
140-
getScopedSlotRenderFunctions(this).map(x =>
141-
this.$options.parent._vnode.data.scopedSlots[x]()
142-
)
123+
const attrs = componentOptions.functional
124+
? {
125+
...context.props,
126+
...context.data.attrs,
127+
class: createClassString(
128+
context.data.staticClass,
129+
context.data.class
130+
)
131+
}
132+
: {
133+
...this.$props
134+
}
135+
136+
const slots = context ? context.slots() : this._renderProxy.$slots
137+
138+
// ensure consistent ordering of slots (default first, then alphabetical)
139+
const sortedSlotEntries = Object.entries(slots)
140+
sortedSlotEntries.sort(([slotNameA], [slotNameB]) =>
141+
slotNameA === 'default'
142+
? -1
143+
: slotNameB === 'default'
144+
? 1
145+
: slotNameA.localeCompare(slotNameB)
146+
)
147+
148+
const children = sortedSlotEntries.map(([slotName, slotChildren]) =>
149+
slotName === 'default'
150+
? slotChildren
151+
: h('template-stub', { attrs: { slot: slotName } }, slotChildren)
143152
)
153+
154+
return h(tagName, { attrs }, children)
144155
}
145156
}
146157
}

test/specs/shallow-mount.spec.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { compileToFunctions } from 'vue-template-compiler'
22
import Vue from 'vue'
3-
import { mount, shallowMount, createLocalVue } from '@vue/test-utils'
3+
import { mount, shallowMount, createLocalVue } from '~vue/test-utils'
44
import Component from '~resources/components/component.vue'
55
import ComponentWithChild from '~resources/components/component-with-child.vue'
66
import ComponentWithNestedChildren from '~resources/components/component-with-nested-children.vue'
@@ -82,8 +82,9 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'shallowMount', () => {
8282
const TestComponent = {
8383
template: `
8484
<child>
85-
<p slot="header">Hello</p>
86-
<p slot="footer">World</p>
85+
default slot content
86+
<template slot="header">Hello</template>
87+
<template slot="footer"><child /></template>
8788
</child>
8889
`
8990
}
@@ -92,8 +93,11 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'shallowMount', () => {
9293
})
9394
expect(wrapper.html()).to.equal(
9495
'<child-stub>\n' +
95-
' <p>Hello</p>\n' +
96-
' <p>World</p>\n' +
96+
' default slot content\n' +
97+
' <template-stub slot="footer">\n' +
98+
' <child-stub></child-stub>\n' +
99+
' </template-stub>\n' +
100+
' <template-stub slot="header">Hello</template-stub>\n' +
97101
'</child-stub>'
98102
)
99103
})

0 commit comments

Comments
 (0)