import {
injectHTML,
$,
$$,
IE_VERSION,
normalizeHTML,
fireEvent,
getCarrotPos,
setCarrotPos
} from '../../../helpers/index'
// include special tags to test specific features
import '../../../tag/v-dom-1.tag'
import '../../../tag/v-dom-2.tag'
import '../../../tag/timetable.tag'
import '../../../tag/nested-child.tag'
import '../../../tag/top-attributes.tag'
import '../../../tag/preserve-attr.tag'
import '../../../tag/svg-attr.tag'
import '../../../tag/named-child.tag'
import '../../../tag/deferred-mount.tag'
import '../../../tag/prevent-update.tag'
import '../../../tag/expression-eval-count.tag'
import '../../../tag/multi-named.tag'
import '../../../tag/named-data-ref.tag'
import '../../../tag/input-number.tag'
import '../../../tag/input-values.tag'
import '../../../tag/input-updated.tag'
import '../../../tag/nested-riot.tag'
import '../../../tag/treeview.tag'
import '../../../tag/events.tag'
import '../../../tag/runtime-event-listener-switch.tag'
import '../../../tag/should-update.tag'
import '../../../tag/should-update-opts.tag'
import '../../../tag/observable-attr.tag'
import '../../../tag/virtual-nested-unmount.tag'
import '../../../tag/virtual-conditional.tag'
import '../../../tag/form-controls.tag'
import '../../../tag/data-is.tag'
import '../../../tag/virtual-nested-component.tag'
import '../../../tag/dynamic-data-is.tag'
import '../../../tag/update-context.tag'
import '../../../tag/dynamic-virtual.tag'
import '../../../tag/multiple-select.tag'
import '../../../tag/dynamic-nested.tag'
import '../../../tag/bug-2629.tag'
describe('Riot core', function() {
it('Riot exists', function () {
expect(riot).to.be.not.undefined
})
before(function() {
// general tag
riot.tag('test', '<p>val: { opts.val }</p>')
})
it('it should export the current riot build version as string', function() {
expect(riot.version).to.be.a('string')
})
it('populates the vdom property correctly on riot global', function() {
injectHTML('<v-dom-1></v-dom-1>')
injectHTML('<v-dom-2></v-dom-2>')
var tags = riot.mount('v-dom-1, v-dom-2')
expect(tags.length).to.be.equal(2)
expect(riot.util.vdom).to.have.length(tags.length)
riot.util.vdom.forEach(function(tag, i) {
expect(tag).to.be.equal(tags[i])
})
tags.forEach(tag => tag.unmount())
})
it('riot can be extended', function() {
riot.route = function() {}
expect(riot.route).to.be.a('function')
riot.util.tmpl.errorHandle = function() {}
expect(riot.util.tmpl.errorHandle).to.be.a('function')
})
it('mount and unmount', function() {
injectHTML([
'<test id="test-tag"></test>',
'<div id="foo"></div>',
'<div id="bar"></div>'
])
var tag = riot.mount('test', { val: 10 })[0],
tag2 = riot.mount('#foo', 'test', { val: 30 })[0],
tag3 = riot.mount($('#bar'), 'test', { val: 50 })[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>val: 10</p>')
expect(normalizeHTML(tag2.root.innerHTML)).to.be.equal('<p>val: 30</p>')
expect(normalizeHTML(tag3.root.innerHTML)).to.be.equal('<p>val: 50</p>')
tag.unmount()
tag2.unmount()
tag3.unmount(true)
expect(tag3.isMounted).to.be.equal(false)
expect($$('test').length).to.be.equal(0)
expect($('#foo')).to.be.equal(null)
expect($('#bar')).to.not.be.equal(null)
expect(tag.root._tag).to.be.equal(undefined)
expect(tag2.root._tag).to.be.equal(undefined)
expect(tag3.root._tag).to.be.equal(undefined)
tag3.root.parentNode.removeChild(tag3.root)
})
it('node should not preserve attributes from tag mounted on it when it is unmounted', function() {
injectHTML('<div id="node"></div>')
var tag = riot.mount('#node', 'top-attributes', { cls: 'test' })[0]
expect(tag.root.hasAttribute('class')).to.be.equal(true)
expect(tag.root.hasAttribute('style')).to.be.equal(true)
expect(tag.root.hasAttribute('data-nqlast')).to.be.equal(true)
tag.unmount()
expect(tag.root.hasAttribute('class')).to.be.equal(false)
expect(tag.root.hasAttribute('style')).to.be.equal(false)
expect(tag.root.hasAttribute('data-nqlast')).to.be.equal(false)
})
it('mount a tag mutiple times', function() {
injectHTML([
// mount the same tag multiple times
'<div id="multi-mount-container-1"></div>'
])
var tag = riot.mount('#multi-mount-container-1', 'test', { val: 300 })[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>val: 300</p>')
riot.tag('test-h', '<p>{ x }</p>', function() { this.x = 'ok'})
tag = riot.mount('#multi-mount-container-1', 'test-h')[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>ok</p>')
tag.unmount()
})
it('compiles and unmount the children tags', function(done) {
injectHTML('<timetable></timetable>')
this.timeout(5000)
var ticks = 0,
tag = riot.mount('timetable', {
start: 0,
ontick: function() {
ticks++
}
})[0]
expect($$('timer', tag.root).length).to.be.equal(3)
riot.update()
expect(tag.tags.foo).to.not.be.equal(undefined)
tag.unmount()
// no time neither for one tick
// because the tag got unMounted too early
setTimeout(function() {
expect(ticks).to.be.equal(0)
done()
}, 1200)
})
it('mount a tag mutiple times using "*"', function() {
injectHTML([
// multple mount using *
'<div id="multi-mount-container-2">',
' <test-i></test-i>',
' <test-l></test-l>',
' <test-m></test-m>',
'</div>'
])
riot.tag('test-i', '<p>{ x }</p>', function() { this.x = 'ok'})
riot.tag('test-l', '<p>{ x }</p>', function() { this.x = 'ok'})
riot.tag('test-m', '<p>{ x }</p>', function() { this.x = 'ok'})
const container = $('#multi-mount-container-2')
var subTags = riot.mount('#multi-mount-container-2', '*')
expect(subTags.length).to.be.equal(3)
subTags = riot.mount(container, '*')
expect(subTags.length).to.be.equal(3)
subTags.forEach(tag => tag.unmount())
container.parentNode.removeChild(container)
})
it('avoid to mount unregistered tags', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<p>hello</p>')
riot.unregister('riot-tmp')
const tags = riot.mount('*')
expect(tags).to.be.have.length(0)
const node = $('riot-tmp')
node.parentNode.removeChild(node)
})
it('remove style of unregistered tags out of document', function() {
injectHTML('<riot-tmp-with-style></riot-tmp-with-style>')
try {
riot.tag('riot-tmp-with-style', '<p>hello</p>', 'riot-tmp-with-style { font-size: 1rem; }')
riot.mount('*') // ensure <style> updated
riot.unregister('riot-tmp-with-style')
riot.mount('*') // ensure <style> updated
$$('head style').forEach(style => {
expect(style.textContent).not.to.contain('riot-tmp-with-style')
})
} finally {
const node = $('riot-tmp-with-style')
node.parentNode.removeChild(node)
}
})
it('an <option> tag having the attribute "selected" should be the value of the parent <select> tag', function() {
injectHTML('<tmp-select-tag></tmp-select-tag>')
riot.tag('tmp-select-tag', `
<select ref='select'>
<option value="1" selected="{v == 1}">1</option>
<option value="2" selected="{v == 2}">2</option>
<option value="3" selected="{v == 3}">3</option>
</select>`,
function() {
this.v = 2
})
var tag = riot.mount('tmp-select-tag')[0]
expect(tag.refs.select.selectedIndex).to.be.equal(1)
tag.unmount()
riot.unregister('tmp-select-tag')
})
it('the mount method could be triggered also on several tags using a NodeList instance', function() {
injectHTML([
'<multi-mount value="1"></multi-mount>',
'<multi-mount value="2"></multi-mount>',
'<multi-mount value="3"></multi-mount>',
'<multi-mount value="4"></multi-mount>'
])
riot.tag('multi-mount', '{ opts.value }')
var multipleTags = riot.mount($$('multi-mount'))
expect(multipleTags[0].root.innerHTML).to.be.equal('1')
expect(multipleTags[1].root.innerHTML).to.be.equal('2')
expect(multipleTags[2].root.innerHTML).to.be.equal('3')
expect(multipleTags[3].root.innerHTML).to.be.equal('4')
multipleTags.forEach(tag => tag.unmount())
})
it('all the nested tags will are correctly pushed to the parent.tags property', function() {
injectHTML('<nested-child></nested-child>')
var tag = riot.mount('nested-child')[0]
expect(tag.tags.child.length).to.be.equal(6)
expect(tag.tags['another-nested-child']).to.be.an('object')
tag.tags.child[0].unmount()
expect(tag.tags.child.length).to.be.equal(5)
tag.tags['another-nested-child'].unmount()
expect(tag.tags['another-nested-child']).to.be.equal(undefined)
tag.unmount()
})
it('brackets', function() {
injectHTML([
'<test-a></test-a>',
'<test-b></test-b>',
'<test-c></test-c>',
'<test-d></test-d>',
'<test-e></test-e>',
'<test-f></test-f>',
'<test-g></test-g>'
])
var tag
riot.settings.brackets = '[ ]'
riot.tag('test-a', '<p>[ x ]</p>', function() { this.x = 'ok'})
tag = riot.mount('test-a')[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>ok</p>')
tag.unmount()
riot.settings.brackets = '${ }'
riot.tag('test-c', '<p>${ x }</p>', function() { this.x = 'ok' })
tag = riot.mount('test-c')[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>ok</p>')
tag.unmount()
riot.settings.brackets = null
riot.tag('test-d', '<p>{ x }</p>', function() { this.x = 'ok' })
tag = riot.mount('test-d')[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>ok</p>')
tag.unmount()
riot.settings.brackets = '[ ]'
riot.tag('test-e', '<p>[ x ]</p>', function() { this.x = 'ok' })
tag = riot.mount('test-e')[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>ok</p>')
tag.unmount()
riot.settings.brackets = '${ }'
riot.tag('test-f', '<p>${ x }</p>', function() { this.x = 'ok' })
tag = riot.mount('test-f')[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>ok</p>')
tag.unmount()
riot.settings.brackets = null
riot.tag('test-g', '<p>{ x }</p>', function() { this.x = 'ok' })
tag = riot.mount('test-g')[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>ok</p>')
tag.unmount()
})
it('the case of attributes prefixed with riot should be leaved untouched', function() {
riot.tag('crazy-svg', `
<svg preserveAspectRatio="xMinYMax meet" riot-viewBox="{'0 0 300 300'}">
<circle riot-cx="{ 5 }" riot-cy="{ 5 }" r="2" fill="black"></circle>
</svg>
`)
injectHTML('<crazy-svg></crazy-svg>')
var tag = riot.mount('crazy-svg')[0]
expect($('svg', tag.root).getAttribute('viewBox')).to.be.equal('0 0 300 300')
expect($('svg', tag.root).getAttribute('preserveAspectRatio')).to.be.equal('xMinYMax meet')
tag.unmount()
})
it('data-is attribute', function() {
injectHTML('<div id="rtag" data-is="rtag"></div>')
riot.tag('rtag', '<p>val: { opts.val }</p>')
var tag = riot.mount('#rtag', { val: 10 })[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>val: 10</p>')
tag.unmount()
expect($$('rtag').length).to.be.equal(0)
tag.unmount()
})
it('the data-is attribute is preserved in case of unmount', function() {
injectHTML('<div id="rtag" data-is="rtag"></div>')
riot.tag('rtag', '<p>val: { opts.val }</p>')
var tag = riot.mount('#rtag', { val: 10 })[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>val: 10</p>')
tag.unmount(true)
expect(tag.root.getAttribute('data-is')).to.be.ok
tag.root.parentNode.removeChild(tag.root)
})
it('data-is can be dynamically created by expression', function() {
injectHTML('<dynamic-data-is></dynamic-data-is>')
var tag = riot.mount('dynamic-data-is')[0]
var divs = $$('div', tag.root)
expect($('input', divs[0]).getAttribute('type')).to.be.equal('color')
expect($('input', divs[0]).getAttribute('name')).to.be.equal('aaa')
expect($('input', divs[1]).getAttribute('type')).to.be.equal('color')
expect($('input', divs[2]).getAttribute('type')).to.be.equal('date')
expect($('input', divs[3]).getAttribute('type')).to.be.equal('date')
expect($('input', divs[3]).getAttribute('name')).to.be.equal('calendar')
expect(tag.tags['dynamic-data-toggle']).to.be.an('object')
tag.single = 'color'
tag.toggle = false
tag.intags[0].name = 'ddd'
tag.update()
expect($('input', divs[3]).getAttribute('type')).to.be.equal('color')
expect($('input', divs[3]).getAttribute('name')).to.be.equal('color')
expect(tag.tags['dynamic-data-toggle']).to.be.equal(undefined)
expect($('input', divs[0]).getAttribute('name')).to.be.equal('ddd')
tag.intags.reverse()
tag.toggle = true
tag.update()
divs = $$('div', tag.root)
expect($('input', divs[0]).getAttribute('type')).to.be.equal('date')
expect($('input', divs[1]).getAttribute('type')).to.be.equal('color')
expect($('input', divs[2]).getAttribute('type')).to.be.equal('color')
expect(tag.tags['dynamic-data-toggle']).to.be.an('object')
tag.intags.splice(1, 1)
tag.update()
expect(tag.tags.color.length).to.be.equal(2) // single + remaining loop color
expect(tag.tags.calendar).to.be.an('object')
// below checks for strays
tag.intags.reverse()
tag.update()
expect(tag.tags.color.length).to.be.equal(2)
tag.intags.reverse()
tag.update()
expect(tag.tags.color.length).to.be.equal(2)
// single tags as tag object and not array after delete
tag.intags.splice(1, 1)
tag.update()
expect(tag.tags.color).to.be.an('object')
tag.unmount()
})
it('support `data-is` for html5 compliance', function() {
injectHTML('<div data-is="tag-data-is"></div>')
var tag = riot.mount('tag-data-is')[0]
var els = $$('p', tag.root)
expect(els.length).to.be.equal(2)
expect(els[0].innerHTML).to.contain('html5')
expect(els[1].innerHTML).to.contain('too')
tag.unmount()
})
it('`data-is` expressions will be evaluated only if they return a string', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', `
<div data-is="{ tag }">
<p>hello</p>
</div>
`)
var tag = riot.mount('riot-tmp')[0]
expect($('p', tag.root).innerHTML).to.be.equal('hello')
tag.unmount()
})
it('tag names are case insensitive (converted to lowercase) in `riot.mount`', function() {
var i, els = $$('tag-data-is,[data-is="tag-data-is"]')
for (i = 0; i < els.length; i++) {
els[i].parentNode.removeChild(els[i])
}
injectHTML('<div data-is="tag-data-is"></div>')
injectHTML('<tag-DATA-Is></tag-DATA-Is>')
var tags = riot.mount('tag-Data-Is')
expect(tags.length).to.be.equal(2)
expect($$('p', tags[0].root).length).to.be.equal(2)
expect($$('p', tags[1].root).length).to.be.equal(2)
tags.push(tags[0], tags[1])
})
it('the data-is attribute gets updated if a DOM node gets mounted using two or more different tags', function() {
var div = document.createElement('div')
var tag1 = riot.mount(div, 'timetable')[0]
expect(div.getAttribute('data-is')).to.be.equal('timetable')
var tag2 = riot.mount(div, 'test')[0]
expect(div.getAttribute('data-is')).to.be.equal('test')
tag1.unmount()
tag2.unmount()
})
it('the value of the `data-is` attribute needs lowercase names', function() {
var i, els = $$('tag-data-is,[data-is="tag-data-is"]')
for (i = 0; i < els.length; i++) {
els[i].parentNode.removeChild(els[i])
}
injectHTML('<div data-is="tag-DATA-Is"></div>')
var tags = riot.mount('tag-Data-Is')
expect(tags.length).to.be.equal(0)
})
it('data-is as expression', function() {
injectHTML('<container-riot></container-riot>')
var tag = riot.mount('container-riot')[0]
var div = $('div', tag.root)
expect(div.getAttribute('data-is')).to.be.equal('nested-riot')
tag.unmount()
})
it('data-is attribute by tag name', function() {
// data-is attribute by tag name
riot.tag('rtag2', '<p>val: { opts.val }</p>')
injectHTML('<div data-is="rtag2"></div>')
var tag = riot.mount('rtag2', { val: 10 })[0]
expect(normalizeHTML(tag.root.innerHTML)).to.be.equal('<p>val: 10</p>')
tag.unmount()
expect($$('rtag2').length).to.be.equal(0)
})
it('data-is attribute using the "*" selector', function() {
injectHTML([
'<div id="rtag-nested">',
' <div data-is="rtag"></div>',
' <div data-is="rtag"></div>',
' <div data-is="rtag"></div>',
'</div>'
])
var subTags = riot.mount('#rtag-nested', '*', { val: 10 })
expect(subTags.length).to.be.equal(3)
expect(normalizeHTML(subTags[0].root.innerHTML)).to.be.equal('<p>val: 10</p>')
expect(normalizeHTML(subTags[1].root.innerHTML)).to.be.equal('<p>val: 10</p>')
expect(normalizeHTML(subTags[2].root.innerHTML)).to.be.equal('<p>val: 10</p>')
subTags.forEach(tag => tag.unmount())
})
it('top level attr manipulation', function() {
injectHTML('<top-level-attr value="initial"></top-level-attr>')
riot.tag('top-level-attr', '{opts.value}')
var tag = riot.mount('top-level-attr')[0]
tag.root.setAttribute('value', 'changed')
tag.update()
expect(tag.root.innerHTML).to.be.equal('changed')
tag.unmount()
})
it('SVGs xlink attributes get correctly parsed', function() {
injectHTML('<svg-attr></svg-attr>')
var tag = riot.mount('svg-attr')[0]
expect(tag.refs.target.getAttributeNS('http://www.w3.org/1999/xlink', 'href')).to.be.equal(tag.href)
tag.unmount()
})
it('preserve attributes from tag definition', function() {
injectHTML('<preserve-attr></preserve-attr><div data-is="preserve-attr2"></div>')
var tag = riot.mount('preserve-attr')[0]
expect(tag.root.className).to.be.equal('single-quote')
var tag2 = riot.mount('preserve-attr2')[0]
expect(tag2.root.className).to.be.equal('double-quote')
tag.unmount()
tag2.unmount()
})
it('precompiled tag compatibility', function() {
injectHTML('<precompiled></precompiled>')
riot.tag('precompiled', 'HELLO!', 'precompiled, [data-is="precompiled"] { color: red }', function(opts) {
this.nothing = opts.nothing
})
var tag = riot.mount('precompiled')[0]
expect(window.getComputedStyle(tag.root, null).color).to.be.equal('rgb(255, 0, 0)')
tag.unmount()
})
it('static referenced tag for tags property', function() {
injectHTML('<named-child-parent></named-child-parent>')
var tag = riot.mount('named-child-parent')[0]
expect(tag.refs['tags-child'].root.innerHTML).to.be.equal('I have a name')
tag.unmount()
})
it('preserve the mount order, first the parent and then all the children', function() {
injectHTML('<deferred-mount></deferred-mount>')
var correctMountingOrder = [
'deferred-mount',
'deferred-child-1',
'deferred-child-2',
'deferred-loop',
'deferred-loop',
'deferred-loop',
'deferred-loop',
'deferred-loop'
],
mountingOrder = [],
cb = function(tagName, childTag) {
// make sure the mount event gets triggered when all the children tags
// are in the DOM
expect(document.contains(childTag.root)).to.be.equal(true)
mountingOrder.push(tagName)
},
tag = riot.mount('deferred-mount', { onmount: cb })[0]
expect(mountingOrder.join()).to.be.equal(correctMountingOrder.join())
tag.unmount()
})
it('no update should be triggered if the preventUpdate flag is set', function() {
injectHTML('<prevent-update></prevent-update>')
var tag = riot.mount('prevent-update')[0]
expect(tag.refs['fancy-name'].innerHTML).to.be.equal('john')
fireEvent($$('p')[0], 'click')
expect(tag.refs['fancy-name'].innerHTML).to.be.equal('john')
tag.unmount()
})
it('the before events get triggered', function() {
injectHTML('<before-events></before-events>')
var tag,
incrementEvents = sinon.spy()
riot.tag('before-events', '', function() {
this.on('before-mount', incrementEvents)
this.on('before-unmount', incrementEvents)
})
tag = riot.mount(document.createElement('before-events'))[0]
tag.unmount()
expect(incrementEvents).to.have.been.calledTwice
})
it('the before mount event gets triggered before the component markup creation', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', `
<p>{ flag }<p>
`, function() {
this.flag = true
this.on('before-mount', () => {
this.flag = false
})
})
var tag = riot.mount('riot-tmp')[0]
expect($('p', tag.root).innerHTML).to.be.equal('false')
tag.unmount()
})
it('all the events get fired also in the loop tags, the e.item property gets preserved', function() {
injectHTML('<events></events>')
var currentItem,
currentIndex,
callbackCalls = 0,
tag = riot.mount('events', {
cb: function(e) {
expect(e.item.val).to.be.equal(currentItem)
expect(e.item.index).to.be.equal(currentIndex)
callbackCalls++
}
})[0],
divTags = $$('div', tag.root)
currentItem = tag.items[0]
currentIndex = 0
fireEvent(divTags[0], 'click')
tag.items.reverse()
tag.update()
currentItem = tag.items[0]
currentIndex = 0
fireEvent(divTags[0], 'click')
expect(callbackCalls).to.be.equal(2)
tag.unmount()
})
it('event listeners can be switched in runtime without memory leaks', function() {
injectHTML('<runtime-event-listener-switch></runtime-event-listener-switch>')
var
args = [],
cb = function(name) {
args.push(name)
},
tag = riot.mount('runtime-event-listener-switch', { cb })[0],
pFirst = $('p.first', tag.root),
pSecond = $('p.second', tag.root)
fireEvent(pFirst, 'click')
expect(args[0]).to.be.equal('ev1')
fireEvent(pSecond, 'mouseenter')
expect(args[1]).to.be.equal('ev2')
fireEvent(pFirst, 'click')
expect(args[2]).to.be.equal('ev1')
fireEvent(pFirst, 'mouseenter')
expect(args[3]).to.be.equal('ev2')
expect(args.length).to.be.equal(4)
tag.unmount()
})
it('don t\' skip the anonymous tags using the "riot.settings.skipAnonymousTags = false" option' , function(done) {
riot.settings.skipAnonymousTags = false
injectHTML('<anonymous-test></anonymous-test>')
riot.mixin({
init() {
if (this.__.isAnonymous) {
expect(this.on).to.be.ok
done()
}
}
})
riot.tag('anonymous-test', '<div each="{ items }"></div>', function() {
this.items = [1]
})
var tag = riot.mount('anonymous-test')[0]
tag.unmount()
riot.settings.skipAnonymousTags = true
})
it('the "riot.settings.skipAnonymousTags = false" option will let trigger the "mount" event on anonymous tags' , function() {
riot.settings.skipAnonymousTags = false
const spy = sinon.spy()
injectHTML('<riot-tmp></riot-tmp>')
riot.mixin({
init() {
this.on('mount', spy)
}
})
riot.tag('riot-tmp', '<div each="{ items }"></div>', function() {
this.items = [1]
})
var tag = riot.mount('riot-tmp')[0]
tag.unmount()
expect(spy).to.have.been.calledTwice
riot.settings.skipAnonymousTags = true
})
it('the "updated" event gets properly triggered in a nested child', function(done) {
injectHTML('<div id="updated-events-tester"></div>')
var tag = riot.mount('#updated-events-tester', 'named-child-parent')[0],
counter = 0
tag.tags['named-child'].on('updated', function() {
counter ++
if (counter === 2) done()
})
tag.update()
tag.tags['named-child'].update()
tag.unmount()
})
it('only evalutes expressions once per update', function() {
injectHTML('<expression-eval-count></expression-eval-count>')
var tag = riot.mount('expression-eval-count')[0]
expect(tag.count).to.be.equal(1)
tag.update()
expect(tag.count).to.be.equal(2)
tag.unmount()
})
it('multi referenced elements to an array', function() {
injectHTML('<multi-named></multi-named>')
var mount = function() {
var tag = this
expect(tag.refs.rad[0].value).to.be.equal('1')
expect(tag.refs.rad[1].value).to.be.equal('2')
expect(tag.refs.rad[2].value).to.be.equal('3')
expect(tag.refs.t.value).to.be.equal('1')
expect(tag.refs.t_1.value).to.be.equal('1')
expect(tag.refs.t_2.value).to.be.equal('2')
expect(tag.refs.c[0].value).to.be.equal('1')
expect(tag.refs.c[1].value).to.be.equal('2')
},
mountChild = function() {
var tag = this
expect(tag.refs.child.value).to.be.equal('child')
expect(tag.refs.check[0].value).to.be.equal('one')
expect(tag.refs.check[1].value).to.be.equal('two')
expect(tag.refs.check[2].value).to.be.equal('three')
}
var tag = riot.mount('multi-named', { mount: mount, mountChild: mountChild })[0]
tag.unmount()
})
it('input type=number', function() {
injectHTML('<input-number></input-number>')
var tag = riot.mount('input-number', {num: 123})[0]
var inp = $('input', tag.root)
expect(inp.getAttribute('type')).to.be.equal('number')
expect(inp.value).to.be.equal('123')
tag = riot.mount('input-number', {num: 0})[0]
inp = $('input', tag.root)
expect(inp.getAttribute('type')).to.be.equal('number')
expect(inp.value).to.be.equal('0')
tag = riot.mount('input-number', {num: null})[0]
inp = $('input', tag.root)
expect(inp.getAttribute('type')).to.be.equal('number')
expect(inp.value).to.be.equal('')
tag.unmount()
})
it('the input values should be updated corectly on any update call', function() {
injectHTML('<input-values></input-values>')
var tag = riot.mount('input-values')[0]
expect(tag.refs.i.value).to.be.equal('hi')
tag.update()
expect(tag.refs.i.value).to.be.equal('foo')
tag.unmount()
})
it('carrot position is preserved when input is same as calculated value', function() {
injectHTML('<input-values></input-values>')
var tag = riot.mount('input-values')[0]
var newValue = 'some new text'
tag.refs.i.value = newValue
tag.refs.i.focus()
setCarrotPos(tag.refs.i, 4)
tag.message = newValue
tag.update()
expect(getCarrotPos(tag.refs.i)).to.be.equal(4)
tag.unmount()
})
it('does not set value attribute', function() {
injectHTML('<input-values></input-values>')
var tag = riot.mount('input-values')[0]
expect(tag.refs.i.value).to.be.equal('hi')
expect(tag.refs.i.hasAttribute('value')).to.be.false
tag.update()
expect(tag.refs.i.value).to.be.equal('foo')
expect(tag.refs.i.hasAttribute('value')).to.be.false
tag.unmount()
})
it('updates the value of input which has been changed from initial one #2096', function() {
injectHTML('<input-updated></input-updated>')
var tag = riot.mount('input-updated')[0]
expect(tag.refs.i.value).to.be.equal('Hello, Riot!')
tag.refs.i.value = 'Hi!'
fireEvent(tag.refs.b, 'click')
expect(tag.refs.i.value).to.be.equal('Can you hear me?')
tag.unmount()
})
it('fails to update the value of input which has the same internal value #1642 #2112', function() {
injectHTML('<input-updated></input-updated>')
var tag = riot.mount('input-updated')[0]
fireEvent(tag.refs.b, 'click')
expect(tag.refs.i.value).to.be.equal('Can you hear me?')
tag.refs.i.value = 'Yeah.'
fireEvent(tag.refs.b, 'click')
expect(tag.refs.i.value).not.to.be.equal('Can you hear me?')
// IT MAY SEEM WEIRD AT FIRST, BUT THIS IS SPEC.
// See more detail on #1642
tag.unmount()
})
it('recursive structure', function() {
injectHTML('<treeview></treeview>')
var tag = riot.mount('treeview')[0]
expect(tag).to.be.an('object')
expect(tag.isMounted).to.be.equal(true)
tag.unmount()
})
it('top most tag preserve attribute expressions', function() {
injectHTML('<top-attributes cls="classy"></top-attributes>')
var tag = riot.mount('top-attributes')[0]
expect(tag.root.className).to.be.equal('classy') // qouted
expect(tag.root.getAttribute('data-noquote')).to.be.equal('quotes') // not quoted
expect(tag.root.getAttribute('data-nqlast')).to.be.equal('quotes') // last attr with no quotes
expect(tag.root.style.fontSize).to.be.equal('2em') // TODO: how to test riot-prefix?
tag.unmount()
})
it('camelize the options passed via dom attributes', function() {
injectHTML('<top-attributes></top-attributes>')
var node = document.createElement('top-attributes'),
tag
node.setAttribute('my-random-attribute', 'hello')
tag = riot.mount(node, {
'another-random-option': 'hello'
})[0]
expect(tag.opts.myRandomAttribute).to.be.equal('hello')
expect(tag.opts['another-random-option']).to.be.equal('hello')
tag.unmount()
})
it('opts could be also an observable object (issue 2581)', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<p>hello</p>')
const [tag] = riot.mount('riot-tmp', riot.observable())
expect(tag.opts.on).to.be.ok
tag.unmount()
})
it('expressions object attributes get removed once used', function() {
injectHTML('<top-attributes></top-attributes>')
var node = document.createElement('top-attributes'),
tag
node.setAttribute('data', '{ opts }')
tag = riot.mount(node, { message: 'hello' })[0]
expect(tag.opts.data.message).to.be.equal('hello')
expect(tag.root.getAttribute('data')).to.be.not.ok
tag.unmount()
})
it('the "shouldUpdate" locks the tag update properly', function() {
injectHTML('<should-update></should-update>')
var tag = riot.mount('should-update')[0]
expect(tag.update()).to.be.ok
expect(tag.refs.count.innerHTML).to.be.equal('0')
expect(tag.count).to.be.equal(0)
tag.update(true)
expect(tag.count).to.be.equal(1)
tag.unmount()
})
it('the "shouldUpdate" accepts nextOpts', function() {
injectHTML('<should-update-opts should-update="{ count === 0 }"></should-update-opts>')
var tag = riot.mount('should-update-opts')[0]
expect(tag.update()).to.be.ok
expect(tag.count).to.be.equal(1)
tag.update()
expect(tag.count).to.be.equal(1)
tag.unmount()
})
it('allow passing riot.observale instances to the children tags', function() {
injectHTML('<observable-attr></observable-attr>')
var tag = riot.mount('observable-attr')[0]
expect(tag.tags['observable-attr-child'].wasTriggered).to.be.equal(true)
tag.unmount()
})
it('nested virtual tags unmount properly', function() {
injectHTML('<virtual-nested-unmount></virtual-nested-unmount>')
var tag = riot.mount('virtual-nested-unmount')[0]
var spans = $$('span', tag.root)
var divs = $$('div', tag.root)
expect(spans.length).to.be.equal(6)
expect(divs.length).to.be.equal(3)
expect(spans[0].innerHTML).to.be.equal('1')
expect(spans[1].innerHTML).to.be.equal('1')
expect(spans[2].innerHTML).to.be.equal('2')
expect(spans[3].innerHTML).to.be.equal('1')
expect(spans[4].innerHTML).to.be.equal('2')
expect(spans[5].innerHTML).to.be.equal('3')
expect(divs[0].innerHTML).to.be.equal('1')
expect(divs[1].innerHTML).to.be.equal('2')
expect(divs[2].innerHTML).to.be.equal('3')
tag.childItems = [
{title: '4', childchildItems: ['1', '2', '3', '4']},
{title: '5', childchildItems: ['1', '2', '3', '4', '5']}
]
tag.update()
spans = $$('span', tag.root)
divs = $$('div', tag.root)
expect(spans.length).to.be.equal(9)
expect(divs.length).to.be.equal(2)
expect(spans[0].innerHTML).to.be.equal('1')
expect(spans[1].innerHTML).to.be.equal('2')
expect(spans[2].innerHTML).to.be.equal('3')
expect(spans[3].innerHTML).to.be.equal('4')
expect(spans[4].innerHTML).to.be.equal('1')
expect(spans[5].innerHTML).to.be.equal('2')
expect(spans[6].innerHTML).to.be.equal('3')
expect(spans[7].innerHTML).to.be.equal('4')
expect(spans[8].innerHTML).to.be.equal('5')
expect(divs[0].innerHTML).to.be.equal('4')
expect(divs[1].innerHTML).to.be.equal('5')
tag.unmount()
})
it('render tag: input,option,textarea tags having expressions as value', function() {
injectHTML('<form-controls></form-controls>')
var val = 'my-value',
tag = riot.mount('form-controls', { text: val })[0],
root = tag.root
expect($('input[type="text"]', root).value).to.be.equal(val)
expect($('select option[selected]', root).value).to.be.equal(val)
expect($('textarea[name="txta1"]', root).value).to.be.equal(val)
expect($('textarea[name="txta2"]', root).value).to.be.equal('')
if (IE_VERSION !== 9) expect($('textarea[name="txta2"]', root).placeholder).to.be.equal(val)
tag.unmount()
})
it('multiple select will be properly rendered', function() {
injectHTML('<multiple-select></multiple-select>')
const tag = riot.mount('multiple-select')[0]
const values = []
;[].forEach.call(tag.refs.sel.options, function(option) {
if (option.selected) values.push(option.value)
})
expect(values).to.have.length(2)
tag.unmount()
})
it('component nested in virtual unmounts correctly', function() {
injectHTML('<virtual-nested-component></virtual-nested-component>')
var tag = riot.mount('virtual-nested-component')[0]
var components = $$('not-virtual-component2', tag.root)
expect(components.length).to.be.equal(4)
expect(tag.tags['not-virtual-component2']).to.have.length(4)
tag.people.pop()
tag.update()
components = $$('not-virtual-component2', tag.root)
expect(components.length).to.be.equal(3)
expect(tag.tags['not-virtual-component2']).to.have.length(3)
tag.unmount()
components = $$('not-virtual-component2', tag.root)
expect(components.length).to.be.equal(0)
})
it('event handler on each custom tag doesnt update parent', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('inner', '<button ref="btn" onclick="{foo}" />', function() {
this.foo = function() {}.bind()
})
riot.tag('riot-tmp', '<inner each="{item in items}" />', function() {
this.items = [1]
this.updateCount = 0
this.on('update', function() { this.updateCount++ })
})
var tag = riot.mount('riot-tmp')[0]
expect(tag.updateCount).to.be.equal(0)
fireEvent(tag.tags.inner[0].refs.btn, 'click')
expect(tag.updateCount).to.be.equal(0)
tag.unmount()
})
it('the class attributes get properly removed in case of falsy values', function(done) {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<p class="{ foo: isFoo }">foo</p>', function() {
this.isFoo = true
})
var tag = riot.mount('riot-tmp')[0],
p = $('p', tag.root)
expect(p.hasAttribute('class')).to.be.equal(true)
// Edge 16 has some race condition issues so we need to defer this check
setTimeout(() => {
tag.isFoo = false
tag.update()
expect(p.hasAttribute('class')).to.be.equal(false)
tag.unmount()
done()
}, 100)
})
it('custom attributes should not be removed if not falsy', function() {
injectHTML('<riot-tmp data-index="{ index }"></riot-tmp>')
riot.tag('riot-tmp', '<p></p>', function() {
this.index = 0
})
var tag = riot.mount('riot-tmp')[0]
expect(tag.opts.dataIndex).to.be.equal(0)
expect(tag.root.getAttribute('data-index')).to.be.ok
tag.index = false
tag.update()
expect(tag.root.getAttribute('data-index')).to.be.not.ok
tag.unmount()
})
it('make sure the tag context is preserved during updates', function(done) {
injectHTML('<update-context></update-context>')
var tag = riot.mount('update-context')[0]
expect(tag.message).to.be.equal('hi')
tag.on('updated', function() {
expect($('p', this.root).textContent).to.be.equal('goodbye')
expect(tag.unmount()).to.be.an('object')
done()
tag.unmount()
})
})
it('create tags extending the riot.Tag constructor', function() {
class Component extends riot.Tag {
get name() { return 'component' }
get tmpl() { return '<h1 onclick="{ onClick }">{ opts.message } { user }</h1>' }
onCreate() {
this.user = 'dear User'
}
onClick() {
this.user = 'the user is gone'
}
}
var component = new Component(document.createElement('div'), {
message: 'hello'
})
var h1 = $('h1', component.root)
expect(component.opts.message).to.be.equal('hello')
expect(component.user).to.be.equal('dear User')
expect(h1.textContent).to.be.equal('hello dear User')
fireEvent(h1, 'click')
expect(h1.textContent).to.be.equal('hello the user is gone')
// make sure the component is properly registered
injectHTML('<component></component>')
var tag = riot.mount('component', {message: 'hi'})[0]
expect(tag.opts.message).to.be.equal('hi')
tag.unmount()
component.unmount()
})
it('extend existing tags created via riot.Tag constructor', function() {
class Component extends riot.Tag {
get name() { return 'component' }
get tmpl() { return '<h1 onclick="{ onClick }">{ opts.message } { user }</h1>' }
onCreate() {
this.user = 'dear User'
}
onClick() {
this.user = 'the user is gone'
}
}
class SubComponent extends Component {
get name() { return 'sub-component' }
get tmpl() { return '<h2 onclick="{ onClick }">{ opts.message } { user }</h2>' }
}
var subComponent = new SubComponent(document.createElement('div'), {
message: 'hello'
})
var h2 = $('h2', subComponent.root)
expect(subComponent.opts.message).to.be.equal('hello')
expect(subComponent.user).to.be.equal('dear User')
expect(h2.textContent).to.be.equal('hello dear User')
// make sure the sub-component is properly registered
injectHTML('<sub-component></sub-component>')
var tag = riot.mount('sub-component', {message: 'hi'})[0]
expect(tag.opts.message).to.be.equal('hi')
tag.unmount()
subComponent.unmount()
})
it('gets the reference by data-ref attribute', function() {
injectHTML('<named-data-ref></named-data-ref>')
var tag = riot.mount('named-data-ref')[0]
expect(tag.refs.greeting.value).to.be.equal('Hello')
tag.unmount()
})
it('unmounting a tag containing ref will not throw', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<div ref="child" onclick="{ unmount }"></div>', function() {
this.isFoo = true
})
var tag = riot.mount('riot-tmp')[0]
fireEvent(tag.refs.child, 'click')
expect(tag.isMounted).to.be.equal(false)
tag.unmount()
})
it('dom nodes having "ref" attributes and upgraded to tags do not appeart twice in the parent', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp-sub', '<p>hi</p>')
riot.tag('riot-tmp', '<div ref="child"></div>', function() {
this.on('mount', () => {
riot.mount(this.refs.child, 'riot-tmp-sub', { parent: this })
})
})
var tag = riot.mount('riot-tmp')[0]
expect(tag.refs.child).to.be.not.an('array')
expect(tag.refs.child.hasAttribute('ref')).to.be.ok
tag.unmount()
})
it('ref attributes will be removed only if falsy or not strings', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', `
<div ref='child'></div>
<div ref="{ expr }"></div>
<div ref="{ null }"></div>
<div ref="{ false }"></div>
<div ref="{ '' }"></div>
`, function() {
this.expr = 'expr'
})
var tag = riot.mount('riot-tmp')[0],
divs = $$('div', tag.root)
expect(tag.refs.child).to.be.ok
expect(tag.refs.expr).to.be.ok
expect(divs[0].hasAttribute('ref')).to.be.ok
expect(divs[1].hasAttribute('ref')).to.be.ok
expect(divs[2].hasAttribute('ref')).to.be.not.ok
expect(divs[3].hasAttribute('ref')).to.be.not.ok
expect(divs[4].hasAttribute('ref')).to.be.not.ok
tag.unmount()
})
it('virtual tags can be used with dynamic data-is', function() {
injectHTML('<dynamic-virtual></dynamic-virtual>')
var tag = riot.mount('dynamic-virtual')[0]
var first = tag.root.firstElementChild
expect(first.tagName).to.be.equal('P')
expect(first.innerHTML).to.be.equal('yielded data')
tag.render = 'xtag'
tag.update()
first = tag.root.firstElementChild
expect(first.tagName).to.be.equal('SPAN')
expect(first.innerHTML).to.be.equal('virtual data-is')
tag.unmount()
})
it('nested dynamic tags retain data-is attribute', function() {
injectHTML('<dynamic-nested></dynamic-nested>')
var tag = riot.mount('dynamic-nested')[0]
expect(tag.refs.dynamic.root.getAttribute('data-is')).to.be.equal('page-a')
expect(tag.tags['page-a'].root.querySelector('h1').innerHTML).to.be.equal('page-a')
tag.page = 'page-b'
tag.update()
expect(tag.refs.dynamic.root.getAttribute('data-is')).to.be.equal('page-b')
expect(tag.tags['page-b'].root.querySelector('h1').innerHTML).to.be.equal('page-b')
tag.unmount()
})
it('virtual tags with conditional will mount their children tags properly', function() {
injectHTML('<virtual-conditional></virtual-conditional>')
var tag = riot.mount('virtual-conditional')[0]
riot.util.tmpl.errorHandler = function () {
throw new Error('It should render without errors')
}
expect(tag.childMountCount).to.be.equal(0)
tag.user = { name: 'foo' }
tag.update()
expect(tag.childMountCount).to.be.equal(1)
riot.util.tmpl.errorHandler = null
tag.unmount()
})
it('the value attribute on a riot tag gets properly passed as option', function() {
injectHTML('<riot-tmp-value></riot-tmp-value>')
riot.tag('riot-tmp', '<p>{ opts.value }</p>')
riot.tag('riot-tmp-value', '<riot-tmp value="{ value }"></riot-tmp>', function() {
this.value = 'foo'
})
var tag = riot.mount('riot-tmp-value')[0]
expect(tag.tags['riot-tmp'].opts.value).to.be.equal('foo')
expect(tag.tags['riot-tmp'].opts.riotValue).to.be.not.ok
tag.unmount()
})
it('the null attributes should be not transformed to empty strings', function() {
injectHTML('<riot-tmp-value></riot-tmp-value>')
riot.tag('riot-tmp', '<p>{ opts.value }</p>')
riot.tag('riot-tmp-value', '<riot-tmp value="{ null }" value2="{ undefined }"></riot-tmp>')
var tag = riot.mount('riot-tmp-value')[0]
expect(tag.tags['riot-tmp'].opts.value).to.be.equal(null)
expect(tag.tags['riot-tmp'].opts.value2).to.be.equal(undefined)
tag.unmount()
})
it('style properties could be passed also as object', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<p riot-style="{ style }">hi</p>')
var tag = riot.mount('riot-tmp')[0],
p = $('p', this.root)
tag.style = { color: 'red', height: '10px'}
tag.update()
expect(p.style.color).to.be.equal('red')
expect(p.style.height).to.be.equal('10px')
tag.unmount()
})
it('class properties could be passed also as object', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<p class="{ classes }">hi</p>')
var tag = riot.mount('riot-tmp')[0],
p = $('p', this.root)
tag.classes = { foo: true, bar: false }
tag.update()
expect(p.getAttribute('class')).to.be.equal('foo')
tag.classes = { foo: true, bar: true }
tag.update()
expect(p.getAttribute('class')).to.be.equal('foo bar')
tag.unmount()
})
it('undefined text node should not be rendered', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<p>{ message }</p>')
var tag = riot.mount('riot-tmp')[0],
p = $('p', this.root)
expect(p.innerHTML).to.be.not.equal('undefined')
tag.unmount()
})
it('subtags created via is get properly unmounted', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp-sub', '<p>hi</p>')
riot.tag('riot-tmp', '<div if="{ showSub }"><div data-is="{ subTag }"></div></div>')
var tag = riot.mount('riot-tmp')[0],
unmount = sinon.spy()
expect(tag.tags['riot-tmp-sub']).to.be.not.ok
tag.showSub = true
tag.subTag = 'riot-tmp-sub'
tag.update()
expect(tag.tags['riot-tmp-sub']).to.be.ok
tag.tags['riot-tmp-sub'].on('unmount', unmount)
tag.showSub = false
tag.update()
expect(tag.tags['riot-tmp-sub']).to.be.not.ok
expect(unmount).to.have.been.called
tag.unmount()
})
it('riot can mount also inline templates', function() {
injectHTML(`
<riot-tmp>
<p ref="mes">{ message }</p>
<riot-tmp-sub ref="sub" message="{ message }">
<p ref="mes">{ message }</p>
</riot-tmp-sub>
</riot-tmp>`)
riot.tag('riot-tmp', false, function() {
this.message = 'hello'
})
riot.tag('riot-tmp-sub', false, function(opts) {
this.message = opts.message
})
var tag = riot.mount('riot-tmp')[0]
expect(tag.refs.mes.innerHTML).to.be.equal(tag.message)
expect(tag.refs.sub.refs.mes.innerHTML).to.be.equal(tag.message)
tag.unmount()
})
it('tags in an svg context are automatically detected and properly created see #2290', function() {
injectHTML('<svg id="tmpsvg"><g data-is="riot-tmp"></g></svg>')
riot.tag('riot-tmp', '<circle riot-cx="{ 10 + 5 }" riot-cy="{ 10 + 5 }" r="2" fill="black"></circle>')
var tag = riot.mount('riot-tmp')[0],
circle = $('circle', this.root)
expect(circle instanceof HTMLElement).to.be.equal(false)
tag.unmount()
document.body.removeChild(window.tmpsvg)
})
it('disable the auto updates via settings.autoUpdate = false', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<p ref="p" onclick="{ updateMessage }">{ message }</p>', function() {
this.message = 'hi'
this.updateMessage = function() {
this.message = 'goodbye'
}
})
riot.settings.autoUpdate = false
var tag = riot.mount('riot-tmp')[0]
expect(tag.refs.p.innerHTML).to.be.equal(tag.message)
fireEvent(tag.refs.p, 'click')
expect(tag.refs.p.innerHTML).to.be.not.equal(tag.message)
tag.unmount()
riot.settings.autoUpdate = true
})
it('updates during the mount event should properly update the DOM', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<p ref="p">{ message }</p>', function() {
this.message = 'hi'
this.on('mount', () => {
this.message = 'goodbye'
this.update()
})
})
var tag = riot.mount('riot-tmp')[0]
expect(tag.refs.p.innerHTML).to.be.equal('goodbye')
tag.unmount()
})
it('avoid to get ref attributes on yield tags', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<yield ref="foo"/>')
var tag = riot.mount('riot-tmp')[0]
expect(tag.refs.foo).to.be.undefined
tag.unmount()
})
it('remove style attributes if they contain blank values', function() {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', "<p ref='p' riot-style=\"{changed ? 'background-color: green' : ''}\"></p>", function() {
this.changed = true
})
var tag = riot.mount('riot-tmp')[0]
expect(tag.refs.p.hasAttribute('style')).to.be.ok
tag.changed = false
tag.update()
expect(tag.refs.p.hasAttribute('style')).to.be.not.ok
tag.unmount()
})
it('avoid to clean the DOM for the default riot.unmount call', function(done) {
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp-sub', '<p id="{ id }">foo</p>', function() {
this.id = `id-${ this._riot_id }`
this.on('before-unmount', () => {
expect(document.getElementById(this.id)).to.be.ok
done()
})
})
riot.tag('riot-tmp', '<riot-tmp-sub></riot-tmp-sub>')
var tag = riot.mount('riot-tmp')[0]
setTimeout(() => {
expect(document.getElementById(tag.tags['riot-tmp-sub'].id)).to.be.ok
tag.unmount()
}, 100)
})
it('avoid to bind wrong named events handlers (issue #2592)', function() {
const click = sinon.spy()
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '<p ref="p" click="{onClick}"></p>',function() {
this.onClick = click
})
const tag = riot.mount('riot-tmp')[0]
const p = tag.refs.p
fireEvent(p, 'click')
expect(click).to.have.not.been.called
tag.unmount()
})
it('does not attempt to makeReplaceVirtual when parentNode no longer exists in DOM (issue 2614)', function () {
riot.tag('riot-unmountable', '<virtual ref="virtual">Hi</virtual>')
injectHTML('<riot-unmountable></riot-unmountable>')
const tag = riot.mount('riot-unmountable')[0]
const virt = tag.refs.virtual
// unmount the tag; virt.root.parentNode will now be null
tag.unmount()
riot.util.tags.makeReplaceVirtual(virt, virt.root)
// getting to this point proves makeReplaceVirtual returned early (i.e., did not error)
expect(true).to.be.true
})
it('make sure options will be not shared between components via riot.mount (issue 2613)', function () {
injectHTML('<riot-tmp title="Bar"></riot-tmp>')
injectHTML('<riot-tmp></riot-tmp>')
riot.tag('riot-tmp', '{opts.title}')
const tags = riot.mount('riot-tmp', function() {
return { title: 'Baz' }
})
expect(tags[0].opts.title).to.be.equal('Bar')
expect(tags[1].opts.title).to.be.equal('Baz')
tags.forEach(tag => tag.unmount())
})
it('Don\'t remove value attributes with the settings keepValueAttributes=true #2629', function(){
injectHTML('<bug-2629></bug-2629>')
riot.settings.keepValueAttributes = true
const tag = riot.mount('bug-2629')[0]
tag.update()
expect(tag.refs.option.childNodes[1].hasAttribute('value')).to.be.ok
expect(tag.refs.check[1].value).to.be.equal('')
expect(tag.refs.radio[1].value).to.be.equal('')
tag.unmount()
riot.settings.keepValueAttributes = false
})
it('Remove empty attributes with the settings keepValueAttributes=false #2629', function(){
injectHTML('<bug-2629></bug-2629>')
riot.settings.keepValueAttributes = false
const tag = riot.mount('bug-2629')[0]
tag.update()
expect(tag.refs.option.childNodes[1].hasAttribute('value')).to.be.not.ok
expect(tag.refs.check[1].value).to.be.a('string')
expect(tag.refs.radio[1].value).to.be.a('string')
tag.unmount()
})
})