Skip to content

Instantly share code, notes, and snippets.

@chartinger
Created January 11, 2017 10:47
Show Gist options
  • Save chartinger/ca67dc17a5657334adb35357f40ad2b9 to your computer and use it in GitHub Desktop.
Save chartinger/ca67dc17a5657334adb35357f40ad2b9 to your computer and use it in GitHub Desktop.
Simple Vue.js shallow render helper
import Vue from 'vue'
const mockComponent = function (name, props) {
return {
props: props,
render: function (createElement) {
return createElement(name, { props: props })
}
}
}
export const getChildFromSelector = function (parent, selector) {
let domElement = parent.$el.querySelector(selector)
if (domElement == null || parent.$children === undefined) {
return null
}
for (let i = 0; i < parent.$children.length; i++) {
if (parent.$children[i].$el === domElement) {
return parent.$children[i]
}
}
return null
}
const ignoreComponents = function (elements, ignoreList) {
if (elements !== undefined) {
if (elements.constructor === Array) {
throw new Error('Array based component configuration is not supported')
}
Object.entries(elements).forEach(
([key]) => {
Array.push(ignoreList, key.toLowerCase())
}
)
}
}
const mockComponents = function (elements, mocks) {
if (elements !== undefined) {
Object.entries(elements).forEach(([key, value]) => {
mocks[key] = mockComponent(key.toLowerCase(), value.props)
})
}
}
export const shallowMount = function (Component, propsData = {}, mock = false) {
const savedLocalComponents = Component.components
const savedName = Component.name
const savedGlobalComponents = Vue.options.components
const savedIgnoredElements = Vue.config.ignoredElements
const ignoredElements = []
const mocks = {}
Vue.options.components = {}
ignoreComponents(savedGlobalComponents, ignoredElements)
if (mock) {
mockComponents(savedGlobalComponents, mocks)
}
ignoreComponents(savedLocalComponents, ignoredElements)
if (mock) {
mockComponents(savedLocalComponents, mocks)
}
// Prevent recursive rendering
if (Component.name !== undefined) {
Array.push(ignoredElements, Component.name)
Component.name = null
}
Component.components = mocks
Vue.config.ignoredElements = ignoredElements
const testContainer = {
components: {
testcomponent: Component
},
render: function (createElement) {
return createElement('testcomponent', { props: propsData })
}
}
const Ctor = Vue.extend(testContainer)
const vm = new Ctor({ propsData }).$mount()
vm.$children[0].getChildFromSelector = function (selector) { return getChildFromSelector(this, selector) }
Component.components = savedLocalComponents
Component.name = savedName
Vue.options.components = savedGlobalComponents
Vue.options.ignoredElements = savedIgnoredElements
return vm.$children[0]
}
export const output = {
of: function (component) {
return component.$el.outerHTML
}
}
import Vue from 'vue'
import { shallowMount, output } from 'src/helpers/TestHelper'
describe('Test Helper', () => {
describe('Simple Rendering', () => {
it('renders a simple component without alterations', () => {
const componentConfig = {
template: '<div><h1>Simple Component</h1></div>'
}
let component = shallowMount(componentConfig)
expect(output.of(component)).to.equal('<div><h1>Simple Component</h1></div>')
})
it('renders the given props', () => {
const componentConfig = {
props: ['title'],
template: '<h1>{{ title }}</h1>'
}
let component = shallowMount(componentConfig, { title: 'New Title' })
expect(output.of(component)).to.equal('<h1>New Title</h1>')
})
it('renders set data', () => {
const componentConfig = {
data: function () { return { title: 'Title from data' } },
template: '<h1>{{ title }}</h1>'
}
let component = shallowMount(componentConfig)
expect(output.of(component)).to.equal('<h1>Title from data</h1>')
})
it('converts html tags to lower case', () => {
const componentConfig = {
template: '<H1>Some Content</H1>'
}
let component = shallowMount(componentConfig)
expect(output.of(component)).to.equal('<h1>Some Content</h1>')
})
it('converts html attributes to lower case', () => {
const componentConfig = {
template: '<h1 ID="content">Some Content</h1>'
}
let component = shallowMount(componentConfig)
expect(output.of(component)).to.equal('<h1 id="content">Some Content</h1>')
})
})
describe('Shallow Rendering', () => {
it('shallow renders a sub component', () => {
const childConfig = {
template: '<div><h1>Simple Component</h1></div>'
}
const componentConfig = {
template: '<div><child></child></div>',
components: { child: childConfig }
}
let component = shallowMount(componentConfig)
expect(output.of(component)).to.equal('<div><child></child></div>')
})
it('supports object based local component configuration', () => {
const Child = {
template: '<div><h1>Simple Component</h1></div>'
}
const componentConfig = {
template: '<div><child></child></div>',
components: { Child }
}
let component = shallowMount(componentConfig)
expect(output.of(component)).to.equal('<div><child></child></div>')
})
it('does not supports array based local component configuration', () => {
const Child = {
template: '<div><h1>Simple Component</h1></div>'
}
const componentConfig = {
template: '<div><child></child></div>',
components: [ Child ]
}
expect(() => shallowMount(componentConfig)).to.throw('Array based component configuration is not supported')
})
it('does not render the component recursively', () => {
const componentConfig = {
name: 'recursive',
template: '<div><recursive></recursive></div>'
}
let component = shallowMount(componentConfig)
expect(output.of(component)).to.equal('<div><recursive></recursive></div>')
})
it('shallow renders a global registered sub component', () => {
const childConfig = {
template: '<div><h1>Simple Component</h1></div>'
}
Vue.component('child', childConfig)
const componentConfig = {
template: '<div><child></child></div>'
}
let component = shallowMount(componentConfig)
expect(output.of(component)).to.equal('<div><child></child></div>')
})
it('does not create instances of sub components in template per default', () => {
const childConfig = {
template: '<div><h1>Simple Component</h1></div>'
}
const componentConfig = {
template: '<div><child></child></div>',
components: { child: childConfig }
}
let component = shallowMount(componentConfig)
expect(component.$children).to.be.empty
})
describe('Fake sub compoments', () => {
it('can fake subcomponents', () => {
const childConfig = {
template: '<div><h1>Simple Component</h1></div>'
}
const componentConfig = {
template: '<div><child></child></div>',
components: { child: childConfig }
}
let component = shallowMount(componentConfig, {}, true)
expect(component.$children).to.be.length(1)
})
it('can pass props to faked subcomponents', () => {
const childConfig = {
props: ['title'],
template: '<div><h1>{{ title }}</h1></div>'
}
const componentConfig = {
template: '<div><child title="test title"></child></div>',
components: { child: childConfig }
}
let component = shallowMount(componentConfig, {}, true)
expect(component.$children).to.be.length(1)
expect(component.$children[0].title).to.equal('test title')
})
it('changes the attributes in shallow render output of faked components', () => {
const childConfig = {
props: ['title', 'var1'],
template: '<div><h1>{{ title }}</h1></div>'
}
const componentConfig = {
template: '<div><child title="test title" :var1="extra" :id="extra" @click="test" unknown="xyz"></child></div>',
components: { child: childConfig },
data: function () { return { extra: 'some value' } },
methods: { test: function () {} }
}
let component = shallowMount(componentConfig, {}, true)
expect(output.of(component)).to.equal('<div><child id="some value" unknown="xyz"></child></div>')
})
describe('helper method to find components by css selector', () => {
it('returns the component for a given selector', () => {
const childConfig = {
props: ['title'],
template: '<div><h1>{{ title }}</h1></div>'
}
const componentConfig = {
template: '<div><child id="child"></child><child id="next"></child></div>',
components: { child: childConfig }
}
let component = shallowMount(componentConfig, {}, true)
let child = component.getChildFromSelector('#child')
expect(child).not.to.be.null
expect(child).to.equal(component.$children[0])
})
it('returns null if selector method does not find any component', () => {
const childConfig = {
props: ['title'],
template: '<div><h1>{{ title }}</h1></div>'
}
const componentConfig = {
template: '<div><child id="child"></child><child id="next"></child></div>',
components: { child: childConfig }
}
let component = shallowMount(componentConfig, {}, true)
let child = component.getChildFromSelector('#nonexist')
expect(child).to.be.null
})
it('returns null if selected dom element is not a component', () => {
const childConfig = {
props: ['title'],
template: '<div><h1>{{ title }}</h1></div>'
}
const componentConfig = {
template: '<div><child id="child"></child><div id="other"></div></div>',
components: { child: childConfig }
}
let component = shallowMount(componentConfig, {}, true)
let child = component.getChildFromSelector('#other')
expect(child).to.be.null
})
it('returns null if there are no children', () => {
const componentConfig = {
template: '<div><div id="other"></div></div>'
}
let component = shallowMount(componentConfig, {}, true)
expect(component.$children).to.be.empty
let child = component.getChildFromSelector('#other')
expect(child).to.be.null
})
})
})
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment