describe('Directives', function () { var nextTick = require('vue/src/utils').nextTick, VM = require('vue/src/viewmodel') describe('attr', function () { var dir = mockDirective('attr', 'input'), el = dir.el it('should set a truthy attribute value', function () { var value = 'Arrrrrr!' dir.arg = 'value' dir.update(value) assert.strictEqual(el.getAttribute('value'), value) }) it('should set attribute value to `0`', function () { dir.arg = 'value' dir.update(0) assert.strictEqual(el.getAttribute('value'), '0') }) it('should remove an attribute if value is `false`', function () { dir.arg = 'disabled' el.setAttribute('disabled', 'disabled') dir.update(false) assert.strictEqual(el.getAttribute('disabled'), null) }) it('should remove an attribute if value is `null`', function () { dir.arg = 'disabled' el.setAttribute('disabled', 'disabled') dir.update(null) assert.strictEqual(el.getAttribute('disabled'), null) }) it('should remove an attribute if value is `undefined`', function () { dir.arg = 'disabled' el.setAttribute('disabled', 'disabled') dir.update(undefined) assert.strictEqual(el.getAttribute('disabled'), null) }) }) describe('text', function () { var dir = mockDirective('text') dir.bind() it('should work with a string', function () { dir.update('hallo') assert.strictEqual(dir.el.textContent, 'hallo') }) it('should work with a number', function () { dir.update(12345) assert.strictEqual(dir.el.textContent, '12345') }) it('should work with booleans', function () { dir.update(true) assert.strictEqual(dir.el.textContent, 'true') }) it('should work with objects', function () { dir.update({foo:"bar"}) assert.strictEqual(dir.el.textContent, '{"foo":"bar"}') }) it('should be empty with null & undefined', function () { dir.update(null) assert.strictEqual(dir.el.textContent, '') dir.update(undefined) assert.strictEqual(dir.el.textContent, '') }) }) describe('html', function () { var dir = mockDirective('html') it('should work with a string', function () { dir.update('hi!!!') assert.strictEqual(dir.el.innerHTML, 'hi!!!') dir.update('hahalol') assert.strictEqual(dir.el.querySelector('span').textContent, 'haha') }) it('should work with a number', function () { dir.update(12345) assert.strictEqual(dir.el.innerHTML, '12345') }) it('should work with booleans', function () { dir.update(true) assert.strictEqual(dir.el.textContent, 'true') }) it('should work with objects', function () { dir.update({foo:"bar"}) assert.strictEqual(dir.el.textContent, '{"foo":"bar"}') }) it('should be empty with with null & undefined', function () { dir.update(null) assert.strictEqual(dir.el.innerHTML, '') dir.update(undefined) assert.strictEqual(dir.el.innerHTML, '') }) it('should swap html if el is a comment placeholder', function () { var dir = mockDirective('html'), comment = document.createComment('hi'), parent = dir.el parent.innerHTML = 'what!' parent.appendChild(comment) dir.el = comment dir.bind() assert.ok(dir.nodes) var pre = 'what!', after = '', h1 = 'helloworld', h2 = 'whatsup' dir.update(h1) assert.strictEqual(parent.innerHTML, pre + h1 + after) dir.update(h2) assert.strictEqual(parent.innerHTML, pre + h2 + after) }) }) describe('show', function () { var dir = mockDirective('show') it('should be default value when value is truthy', function () { dir.update(1) assert.strictEqual(dir.el.style.display, '') dir.update('hi!') assert.strictEqual(dir.el.style.display, '') dir.update(true) assert.strictEqual(dir.el.style.display, '') dir.update({}) assert.strictEqual(dir.el.style.display, '') dir.update(function () {}) assert.strictEqual(dir.el.style.display, '') }) it('should be none when value is falsy', function () { dir.update(0) assert.strictEqual(dir.el.style.display, 'none') dir.update('') assert.strictEqual(dir.el.style.display, 'none') dir.update(false) assert.strictEqual(dir.el.style.display, 'none') dir.update(null) assert.strictEqual(dir.el.style.display, 'none') dir.update(undefined) assert.strictEqual(dir.el.style.display, 'none') }) }) describe('class', function () { function contains (el, cls) { var cur = ' ' + el.className + ' ' return cur.indexOf(' ' + cls + ' ') > -1 } it('should set class to the value if it has no arg', function () { var dir = mockDirective('class') dir.update('test') assert.ok(contains(dir.el, 'test')) dir.update('hoho') assert.ok(!contains(dir.el, 'test')) assert.ok(contains(dir.el, 'hoho')) }) it('should add/remove class based on truthy/falsy if it has an arg', function () { var dir = mockDirective('class') dir.arg = 'test' dir.update(true) assert.ok(contains(dir.el, 'test')) dir.update(false) assert.ok(!contains(dir.el, 'test')) }) }) describe('model', function () { describe('input[checkbox]', function () { var dir = mockDirective('model', 'input', 'checkbox') dir.bind() before(function () { document.body.appendChild(dir.el) }) it('should set checked on update()', function () { dir.update(true) assert.ok(dir.el.checked) dir.update(false) assert.ok(!dir.el.checked) }) it('should trigger vm.$set when clicked', function () { var triggered = false dir.key = 'foo' dir.ownerVM = { $set: function (key, val) { assert.strictEqual(key, 'foo') assert.strictEqual(val, true) triggered = true }} dir.el.dispatchEvent(mockMouseEvent('click')) assert.ok(triggered) }) it('should remove event listener with unbind()', function () { var removed = true dir.ownerVM = { $set: function () { removed = false } } dir.unbind() dir.el.dispatchEvent(mockMouseEvent('click')) assert.ok(removed) }) after(function () { document.body.removeChild(dir.el) }) }) describe('input[radio]', function () { var dir1 = mockDirective('model', 'input', 'radio'), dir2 = mockDirective('model', 'input', 'radio') dir1.el.name = 'input-radio' dir2.el.name = 'input-radio' dir1.el.value = '12345' dir2.el.value = '54321' dir1.bind() dir2.bind() before(function () { document.body.appendChild(dir1.el) document.body.appendChild(dir2.el) }) it('should set el.checked on update()', function () { assert.notOk(dir1.el.checked) dir1.update(12345) assert.ok(dir1.el.checked) }) it('should trigger vm.$set when clicked', function () { var triggered = false dir2.key = 'radio' dir2.ownerVM = { $set: function (key, val) { triggered = true assert.strictEqual(key, 'radio') assert.strictEqual(val, dir2.el.value) }} dir2.el.dispatchEvent(mockMouseEvent('click')) assert.ok(triggered) assert.ok(dir2.el.checked) assert.notOk(dir1.el.checked) }) it('should remove listeners on unbind()', function () { var removed = true dir1.ownerVM = { $set: function () { removed = false }} dir1.unbind() dir1.el.dispatchEvent(mockMouseEvent('click')) assert.ok(removed) }) after(function () { document.body.removeChild(dir1.el) document.body.removeChild(dir2.el) }) }) describe('select', function () { var dir = mockDirective('model', 'select'), o1 = document.createElement('option'), o2 = document.createElement('option') o1.value = 0 o2.value = 1 dir.el.appendChild(o1) dir.el.appendChild(o2) dir.bind() before(function () { document.body.appendChild(dir.el) }) it('should set value on update()', function () { dir.update(0) assert.strictEqual(dir.el.value, '0') }) it('should trigger vm.$set when value is changed', function () { var triggered = false dir.key = 'select' dir.ownerVM = { $set: function (key, val) { triggered = true assert.strictEqual(key, 'select') assert.equal(val, 1) }} dir.el.options.selectedIndex = 1 dir.el.dispatchEvent(mockHTMLEvent('change')) assert.ok(triggered) }) it('should remove listener on unbind()', function () { var removed = true dir.ownerVM = { $set: function () { removed = false }} dir.unbind() dir.el.dispatchEvent(mockHTMLEvent('change')) assert.ok(removed) }) after(function () { document.body.removeChild(dir.el) }) }) describe('input[text] and others', function () { var dir = mockDirective('model', 'input', 'text') dir.bind() before(function () { document.body.appendChild(dir.el) }) it('should set the value on update()', function () { dir.update('foobar') assert.strictEqual(dir.el.value, 'foobar') }) // `lazy` option is tested in the API suite it('should trigger vm.$set when value is changed via input', function () { var triggered = false dir.key = 'foo' dir.ownerVM = { $set: function (key, val) { assert.ok(dir.lock, 'the directive should be locked if it has no filters') assert.strictEqual(key, 'foo') assert.strictEqual(val, 'bar') triggered = true }} dir.el.value = 'bar' dir.el.dispatchEvent(mockHTMLEvent('input')) assert.ok(triggered) }) it('should remove event listener with unbind()', function () { var removed = true dir.ownerVM = { $set: function () { removed = false } } dir.unbind() dir.el.dispatchEvent(mockHTMLEvent('input')) assert.ok(removed) }) it('should not lock during vm.$set if it has filters', function (done) { var triggered = false var dir = mockDirective('model', 'input', 'text') dir.filters = [] dir.bind() dir.ownerVM = {$set:function () { assert.notOk(dir.lock) triggered = true }} dir.el.value = 'foo' document.body.appendChild(dir.el) dir.el.dispatchEvent(mockHTMLEvent('input')) // timeout becuase the update is async setTimeout(function () { assert.ok(triggered) document.body.removeChild(dir.el) done() }, 1) }) after(function () { document.body.removeChild(dir.el) }) }) }) describe('on', function () { var dir = mockDirective('on') dir.arg = 'click' dir.bind() before(function () { document.body.appendChild(dir.el) }) it('should set the handler to be triggered by arg through update()', function () { var triggered = false dir.update(function () { triggered = true }) dir.el.dispatchEvent(mockMouseEvent('click')) assert.ok(triggered) }) it('should remove previous handler when update() a new handler', function () { var triggered1 = false, triggered2 = false dir.update(function () { triggered1 = true }) dir.update(function () { triggered2 = true }) dir.el.dispatchEvent(mockMouseEvent('click')) assert.notOk(triggered1) assert.ok(triggered2) }) it('should wrap the handler to supply expected args', function () { var vm = dir.binding.compiler.vm, // owner VM e = mockMouseEvent('click'), // original event triggered = false dir.update(function (ev) { assert.strictEqual(this, vm, 'handler should be called on owner VM') assert.strictEqual(ev, e, 'event should be passed in') assert.strictEqual(ev.targetVM, dir.vm) triggered = true }) dir.el.dispatchEvent(e) assert.ok(triggered) }) it('should remove the handler in unbind()', function () { var triggered = false dir.update(function () { triggered = true }) dir.unbind() dir.el.dispatchEvent(mockMouseEvent('click')) assert.notOk(triggered) }) after(function () { document.body.removeChild(dir.el) }) }) describe('pre', function () { it('should skip compilation', function () { var testId = 'pre-test' mock(testId, '{{lol}}') var t = new Vue({ el: '#' + testId, data: { lol: 'heyhey', hi: 'hohoho' } }) assert.strictEqual(t.$el.querySelector('strong').textContent, '{{lol}}') assert.strictEqual(t.$el.querySelector('a').textContent, '') assert.ok(t.$el.querySelector('a').hasAttribute('v-text')) }) }) describe('component', function () { it('should create a child viewmodel with given constructor', function () { var testId = 'component-test' mock(testId, '
') var t = new Vue({ el: '#' + testId, data: { msg: '123' }, components: { 'component-test': { template: '{{msg}}' } } }) assert.strictEqual(t.$el.querySelector('span').textContent, '123') }) }) describe('with', function () { it('should create a child viewmodel with given data', function () { var testId = 'with-test' mock(testId, '{{msg}}') var t = new Vue({ el: '#' + testId, data: { test: { msg: testId } } }) assert.strictEqual(t.$el.querySelector('span').textContent, testId) }) it('should accept args and sync parent and child', function (done) { var t = new Vue({ template: '{{test.msg}} {{n}}' + '{{childMsg}} {{n}}
', data: { n: 1, test: { msg: 'haha!' } } }) nextTick(function () { assert.strictEqual(t.$el.querySelector('span').textContent, 'haha! 1') assert.strictEqual(t.$el.querySelector('p').textContent, 'haha! 1') testParentToChild() }) function testParentToChild () { // test sync from parent to child t.test = { msg: 'hehe!' } nextTick(function () { assert.strictEqual(t.$el.querySelector('p').textContent, 'hehe! 1') testChildToParent() }) } function testChildToParent () { // test sync back t.$.child.childMsg = 'hoho!' t.$.child.n = 2 assert.strictEqual(t.test.msg, 'hoho!') assert.strictEqual(t.n, 2) nextTick(function () { assert.strictEqual(t.$el.querySelector('span').textContent, 'hoho! 2') assert.strictEqual(t.$el.querySelector('p').textContent, 'hoho! 2') done() }) } }) }) describe('ref', function () { var t it('should register a VM isntance on its parent\'s $', function () { var called = false var Child = Vue.extend({ methods: { test: function () { called = true } } }) t = new Vue({ template: '', components: { child: Child } }) assert.ok(t.$.hihi instanceof Child) t.$.hihi.test() assert.ok(called) }) it('should remove the reference if child is destroyed', function () { t.$.hihi.$destroy() assert.notOk('hihi' in t.$) }) it('should register an Array of VMs with v-repeat', function () { t = new Vue({ template: '', data: { list: [{a:1}, {a:2}, {a:3}] } }) assert.equal(t.$.list.length, 3) assert.ok(t.$.list[0] instanceof Vue) assert.equal(t.$.list[1].a, 2) }) it('should work with interpolation', function () { t = new Vue({ template: '', data: { obj: { a: 123 } } }) assert.equal(t.$.b.a, 123) }) }) describe('partial', function () { it('should replace the node\'s content', function () { var t = new Vue({ template: '', partials: { test: 'ahahaha!' } }) assert.strictEqual(t.$el.innerHTML, '') }) it('should work with interpolation', function () { var t = new Vue({ template: '', partials: { a: 'A', b: 'B' }, data: { ready: true } }) assert.strictEqual(t.$el.innerHTML, '