misc_spec.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. // test cases for edge cases & bug fixes
  2. var Vue = require('../../../src/vue')
  3. var _ = require('../../../src/util/debug')
  4. describe('Misc', function () {
  5. beforeEach(function () {
  6. spyOn(_, 'warn')
  7. })
  8. it('should handle directive.bind() altering its childNode structure', function () {
  9. var vm = new Vue({
  10. el: document.createElement('div'),
  11. template: '<div v-test>{{test}}</div>',
  12. data: {
  13. test: 'hi'
  14. },
  15. directives: {
  16. test: {
  17. bind: function () {
  18. this.el.insertBefore(document.createTextNode('yo '),
  19. this.el.firstChild)
  20. }
  21. }
  22. }
  23. })
  24. expect(vm.$el.textContent).toBe('yo hi')
  25. })
  26. it('attached/detached hooks for transcluded components', function () {
  27. var spy1 = jasmine.createSpy('attached')
  28. var spy2 = jasmine.createSpy('detached')
  29. var el = document.createElement('div')
  30. el.innerHTML = '<outer v-ref="outter"><inner></inner></outer>'
  31. document.body.appendChild(el)
  32. var vm = new Vue({
  33. el: el,
  34. components: {
  35. outer: {
  36. template: '<content></content>'
  37. },
  38. inner: {
  39. template: 'hi',
  40. attached: spy1,
  41. detached: spy2
  42. }
  43. }
  44. })
  45. expect(spy1).toHaveBeenCalled()
  46. vm.$.outter.$remove()
  47. expect(spy2).toHaveBeenCalled()
  48. })
  49. it('v-repeat on component root node with replace:true', function () {
  50. var el = document.createElement('div')
  51. var vm = new Vue({
  52. el: el,
  53. template: '<test></test>',
  54. components: {
  55. test: {
  56. data: function () {
  57. return { list: [1, 2, 3] }
  58. },
  59. template: '<div v-repeat="list">{{$value}}</div>',
  60. replace: true
  61. }
  62. }
  63. })
  64. expect(vm.$el.innerHTML).toBe('<div>1</div><div>2</div><div>3</div>')
  65. })
  66. // #922
  67. it('template repeat inside svg', function () {
  68. var el = document.createElement('div')
  69. new Vue({
  70. el: el,
  71. template: '<svg><template v-repeat="list"><text>{{$value}}</text></template></svg>',
  72. data: {
  73. list: [1, 2, 3]
  74. }
  75. })
  76. // IE inlines svg namespace
  77. var xmlns = /\s?xmlns=".*svg"/
  78. expect(el.innerHTML.replace(xmlns, '')).toBe('<svg><text>1</text><text>2</text><text>3</text></svg>')
  79. })
  80. // #1005
  81. it('call lifecycle hooks for child components', function () {
  82. Vue.options.replace = true
  83. var el = document.createElement('div')
  84. var logs = []
  85. function log (n) {
  86. return function () {
  87. logs.push(n)
  88. }
  89. }
  90. document.body.appendChild(el)
  91. var vm = new Vue({
  92. el: el,
  93. attached: log(0),
  94. ready: log(1),
  95. detached: log(2),
  96. beforeDestroy: log(3),
  97. destroyed: log(4),
  98. template: '<div><test></test><test></test></div>',
  99. components: {
  100. test: {
  101. template: '<span>hi</span>',
  102. attached: log(5),
  103. ready: log(6),
  104. detached: log(7),
  105. beforeDestroy: log(8),
  106. destroyed: log(9)
  107. }
  108. }
  109. })
  110. expect(vm.$el.innerHTML).toBe('<span>hi</span><span>hi</span>')
  111. expect(logs.join()).toBe('0,5,6,5,6,1')
  112. logs = []
  113. vm.$destroy(true)
  114. expect(logs.join()).toBe('3,8,9,8,9,2,7,7,4')
  115. Vue.options.replace = false
  116. })
  117. // #1006
  118. it('destroyed hook for components inside v-if', function (done) {
  119. var spy = jasmine.createSpy('v-if destroyed hook')
  120. var vm = new Vue({
  121. el: document.createElement('div'),
  122. template: '<template v-if="ok"><test></test></template>',
  123. data: {
  124. ok: true
  125. },
  126. components: {
  127. test: {
  128. destroyed: spy
  129. }
  130. }
  131. })
  132. vm.ok = false
  133. Vue.nextTick(function () {
  134. expect(spy).toHaveBeenCalled()
  135. done()
  136. })
  137. })
  138. it('frozen model, root', function (done) {
  139. var vm = new Vue({
  140. el: document.createElement('div'),
  141. template: '{{msg}}',
  142. data: Object.freeze({
  143. msg: 'hi!'
  144. })
  145. })
  146. expect(vm.$el.textContent).toBe('hi!')
  147. vm.msg = 'ho!'
  148. Vue.nextTick(function () {
  149. expect(vm.$el.textContent).toBe('hi!')
  150. done()
  151. })
  152. })
  153. it('frozen model, non-root', function (done) {
  154. var vm = new Vue({
  155. el: document.createElement('div'),
  156. template: '{{msg}} {{frozen.msg}}',
  157. data: {
  158. msg: 'hi',
  159. frozen: Object.freeze({
  160. msg: 'frozen'
  161. })
  162. }
  163. })
  164. expect(vm.$el.textContent).toBe('hi frozen')
  165. vm.msg = 'ho'
  166. vm.frozen.msg = 'changed'
  167. Vue.nextTick(function () {
  168. expect(vm.$el.textContent).toBe('ho frozen')
  169. done()
  170. })
  171. })
  172. it('should not trigger deep/Array watchers when digesting', function (done) {
  173. var spy1 = jasmine.createSpy('deep')
  174. var spy2 = jasmine.createSpy('Array')
  175. var spy3 = jasmine.createSpy('test')
  176. var spy4 = jasmine.createSpy('deep-mutated')
  177. var vm = new Vue({
  178. el: 'body',
  179. data: {
  180. obj: {},
  181. arr: [],
  182. obj2: {}
  183. },
  184. watch: {
  185. obj: {
  186. handler: spy1,
  187. deep: true
  188. },
  189. arr: spy2,
  190. // if the watcher is watching the added value,
  191. // it should still trigger properly
  192. test: {
  193. handler: spy3,
  194. deep: true
  195. },
  196. // if the object is in fact mutated, it should
  197. // still trigger.
  198. obj2: {
  199. handler: spy4,
  200. deep: true
  201. }
  202. }
  203. })
  204. var test = []
  205. var obj2 = vm.obj2
  206. vm.$add('test', test)
  207. obj2.$add('test', 123)
  208. Vue.nextTick(function () {
  209. expect(spy1).not.toHaveBeenCalled()
  210. expect(spy2).not.toHaveBeenCalled()
  211. expect(spy3).toHaveBeenCalledWith(test, undefined)
  212. expect(spy4).toHaveBeenCalledWith(obj2, obj2)
  213. done()
  214. })
  215. })
  216. it('strict mode', function () {
  217. Vue.config.strict = true
  218. new Vue({
  219. el: document.createElement('div'),
  220. template: '<test></test>',
  221. components: {
  222. test: {
  223. template: '<div v-strict>hi</div>'
  224. }
  225. },
  226. directives: {
  227. strict: function () {}
  228. }
  229. })
  230. expect(hasWarned(_, 'Failed to resolve directive: strict')).toBe(true)
  231. Vue.config.strict = false
  232. })
  233. it('strict mode for repeat instances', function () {
  234. Vue.config.strict = true
  235. var vm = new Vue({
  236. el: document.createElement('div'),
  237. template: '<div v-repeat="list"><test></test></div>',
  238. data: {
  239. list: [1, 2]
  240. },
  241. components: {
  242. test: {
  243. template: 'hi'
  244. }
  245. }
  246. })
  247. expect(_.warn).not.toHaveBeenCalled()
  248. expect(vm.$el.textContent).toBe('hihi')
  249. Vue.config.strict = false
  250. })
  251. it('class interpolation and v-class should work together', function (done) {
  252. var el = document.createElement('div')
  253. el.setAttribute('class', 'a {{classB}}')
  254. el.setAttribute('v-class', 'c: showC')
  255. var vm = new Vue({
  256. el: el,
  257. data: {
  258. classB: 'b',
  259. showC: true
  260. }
  261. })
  262. assertClasses(['a', 'b', 'c'])
  263. vm.classB = 'bb'
  264. vm.showC = false
  265. Vue.nextTick(function () {
  266. assertClasses(['a', 'bb'])
  267. done()
  268. })
  269. function assertClasses (expectedClasses) {
  270. var classes = el.className.trim().split(/\s+/)
  271. expect(classes.length).toBe(expectedClasses.length)
  272. var has = expectedClasses.every(function (cls) {
  273. return classes.indexOf(cls) > -1
  274. })
  275. expect(has).toBe(true)
  276. }
  277. })
  278. it('handle interpolated textarea', function (done) {
  279. var el = document.createElement('div')
  280. el.innerHTML = '<textarea>hello {{msg}}</textarea>'
  281. var vm = new Vue({
  282. el: el,
  283. data: {
  284. msg: 'test'
  285. }
  286. })
  287. expect(el.innerHTML).toBe('<textarea>hello test</textarea>')
  288. vm.msg = 'world'
  289. Vue.nextTick(function () {
  290. expect(el.innerHTML).toBe('<textarea>hello world</textarea>')
  291. done()
  292. })
  293. })
  294. it('resolveAsset for repeat instance inside content in strict mode', function () {
  295. Vue.config.strict = true
  296. var el = document.createElement('div')
  297. el.innerHTML =
  298. '<outer>' +
  299. '<template v-repeat="item in items">' +
  300. '<inner>{{item}}</inner>' +
  301. '</template>' +
  302. '</outer>'
  303. new Vue({
  304. el: el,
  305. data: {
  306. items: [1, 2, 3]
  307. },
  308. components: {
  309. outer: { template: '<content></content>' },
  310. inner: { template: '<content></content>' }
  311. }
  312. })
  313. expect(el.textContent).toBe('123')
  314. Vue.config.strict = false
  315. })
  316. it('nested object $set should trigger parent array notify', function (done) {
  317. var vm = new Vue({
  318. el: document.createElement('div'),
  319. template: '{{items | json}}{{items[0].a}}',
  320. data: {
  321. items: [{}]
  322. }
  323. })
  324. expect(vm.$el.textContent).toBe(JSON.stringify(vm.items, null, 2))
  325. vm.items[0].$set('a', 123)
  326. Vue.nextTick(function () {
  327. expect(vm.$el.textContent).toBe(JSON.stringify(vm.items, null, 2) + '123')
  328. done()
  329. })
  330. })
  331. })