Created
January 11, 2017 10:47
-
-
Save chartinger/ca67dc17a5657334adb35357f40ad2b9 to your computer and use it in GitHub Desktop.
Simple Vue.js shallow render helper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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