You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

adopter.js 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* globals describe, expect, it, beforeEach, afterEach, jasmine */
  2. import {
  3. create,
  4. makeInstance,
  5. nodeOrNew,
  6. register,
  7. getClass,
  8. eid,
  9. extend,
  10. wrapWithAttrCheck,
  11. Rect,
  12. Element,
  13. root,
  14. G,
  15. Gradient,
  16. Dom,
  17. Path,
  18. Fragment
  19. } from '../../../src/main.js'
  20. import { mockAdopt, assignNewId, adopt } from '../../../src/utils/adopter.js'
  21. import { buildFixtures } from '../../helpers.js'
  22. import { globals, getWindow } from '../../../src/utils/window.js'
  23. import { svg } from '../../../src/modules/core/namespaces.js'
  24. const { any, createSpy, objectContaining } = jasmine
  25. describe('adopter.js', () => {
  26. let Node
  27. beforeEach(() => {
  28. Node = globals.window.Node
  29. })
  30. describe('create()', () => {
  31. it('creates a node of the specified type', () => {
  32. const rect = create('rect')
  33. expect(rect).toEqual(any(Node))
  34. expect(rect.nodeName).toBe('rect')
  35. })
  36. })
  37. describe('makeInstance()', () => {
  38. const adoptSpy = createSpy('adopt', adopt).and.callThrough()
  39. beforeEach(() => {
  40. adoptSpy.calls.reset()
  41. mockAdopt(adoptSpy)
  42. })
  43. afterEach(() => {
  44. mockAdopt()
  45. })
  46. it('creates a root-object when no argument given', () => {
  47. const doc = makeInstance()
  48. expect(doc).toEqual(any(getClass(root)))
  49. expect(doc).toEqual(any(Element))
  50. })
  51. it('returns a given svg.js object directly', () => {
  52. const rect = new Rect()
  53. const samerect = makeInstance(rect)
  54. expect(rect).toBe(samerect)
  55. })
  56. it('creates an element from passed svg string', () => {
  57. const rect = makeInstance('<rect width="200px" />')
  58. expect(adoptSpy).toHaveBeenCalledWith(any(Node))
  59. expect(adoptSpy).toHaveBeenCalledWith(
  60. objectContaining({ nodeName: 'rect' })
  61. )
  62. expect(rect).toEqual(any(Rect))
  63. expect(rect.parent()).toBe(null)
  64. })
  65. it('creates an element in the html namespace from passed html string', () => {
  66. const div = makeInstance('<div />', true)
  67. expect(adoptSpy).toHaveBeenCalledWith(any(Node))
  68. expect(adoptSpy).toHaveBeenCalledWith(
  69. objectContaining({
  70. nodeName: 'DIV',
  71. namespaceURI: 'http://www.w3.org/1999/xhtml'
  72. })
  73. )
  74. expect(div).toEqual(any(Dom))
  75. expect(div.parent()).toBe(null)
  76. })
  77. it('does not have its wrapper attached', () => {
  78. const rect = makeInstance('<rect width="200px" />')
  79. expect(rect.parent()).toBe(null)
  80. })
  81. it('searches for element in dom if selector given', () => {
  82. buildFixtures()
  83. const path = globals.window.document.getElementById('lineAB')
  84. const pathInst = makeInstance('#lineAB')
  85. const noEl = makeInstance('#doesNotExist')
  86. expect(adoptSpy).toHaveBeenCalledWith(path)
  87. expect(adoptSpy).toHaveBeenCalledWith(null)
  88. expect(pathInst).toEqual(any(Path))
  89. expect(noEl).toBe(null)
  90. })
  91. it('calls adopt when passed a node', () => {
  92. const rect = makeInstance(create('rect'))
  93. expect(adoptSpy).toHaveBeenCalledWith(any(Node))
  94. expect(adoptSpy).toHaveBeenCalledWith(
  95. objectContaining({ nodeName: 'rect' })
  96. )
  97. expect(rect).toEqual(any(Rect))
  98. })
  99. })
  100. describe('adopt()', () => {
  101. it('returns null of passed node is null', () => {
  102. expect(adopt(null)).toBe(null)
  103. })
  104. it('returns instance from node if present', () => {
  105. const rect = new Rect()
  106. expect(adopt(rect.node)).toBe(rect)
  107. })
  108. it('creates Fragment when document fragment is passed', () => {
  109. const frag = getWindow().document.createDocumentFragment()
  110. expect(adopt(frag)).toEqual(any(Fragment))
  111. })
  112. it('creates instance when node without instance is passed', () => {
  113. const rect = new Rect()
  114. const node = rect.node
  115. delete node.instance
  116. expect(adopt(node)).toEqual(any(Rect))
  117. expect(adopt(node)).not.toBe(rect)
  118. })
  119. it('creates instance when node without instance is passed with gradients', () => {
  120. const gradient = new Gradient('linear')
  121. const node = gradient.node
  122. delete node.instance
  123. expect(adopt(node)).toEqual(any(Gradient))
  124. expect(adopt(node).type).toBe('linearGradient')
  125. expect(adopt(node)).not.toBe(gradient)
  126. })
  127. it('creates Dom instances for unknown nodes', () => {
  128. const div = getWindow().document.createElement('div')
  129. expect(adopt(div)).toEqual(any(Dom))
  130. })
  131. })
  132. describe('nodeOrNew()', () => {
  133. it('creates a node of node argument is null', () => {
  134. const rect = nodeOrNew('rect', null)
  135. expect(rect).toEqual(any(Node))
  136. expect(rect.nodeName).toBe('rect')
  137. })
  138. it('returns the node if one is passed', () => {
  139. const div = globals.window.document.createElement('div')
  140. const node = nodeOrNew('something', div)
  141. // jasmine chucks on this when using the node directly
  142. expect(node.outerHTML).toBe(div.outerHTML)
  143. })
  144. it('gracefully handles nodes that are not yet imported into the document', () => {
  145. const otherDoc = globals.document.implementation.createDocument(
  146. svg,
  147. 'svg'
  148. )
  149. const rect = otherDoc.createElementNS(svg, 'rect')
  150. const node = nodeOrNew('rect', rect)
  151. expect(node).toEqual(rect)
  152. })
  153. })
  154. describe('register()/getClass()', () => {
  155. it('sets and gets a class from the class register', () => {
  156. const A = class {}
  157. register(A)
  158. expect(getClass('A')).toBe(A)
  159. })
  160. })
  161. describe('eid()', () => {
  162. it('returns a unique id', () => {
  163. expect(eid('foo')).not.toBe(eid('foo'))
  164. })
  165. })
  166. describe('assignNewId()', () => {
  167. it('assigns a new id if id is present on element', () => {
  168. const rect = new Rect().id('foo')
  169. assignNewId(rect.node)
  170. expect(rect.id()).not.toBe('foo')
  171. })
  172. it('does not set id if no id is present on element', () => {
  173. const rect = new Rect()
  174. assignNewId(rect.node)
  175. expect(rect.attr('id')).toBe(undefined)
  176. })
  177. it('recursively sets new ids on children', () => {
  178. const group = new G().id('foo')
  179. const rect = group.rect(100, 100).id('bar')
  180. assignNewId(group.node)
  181. expect(group.id()).not.toBe('foo')
  182. expect(rect.id()).not.toBe('bar')
  183. })
  184. })
  185. describe('extend()', () => {
  186. it('adds all functions in the given object to the target object', () => {
  187. const A = class {}
  188. extend(A, {
  189. test() {
  190. this.prop = 'test'
  191. return this
  192. }
  193. })
  194. expect(typeof A.prototype.test).toBe('function')
  195. expect(new A().test().prop).toBe('test')
  196. })
  197. it('accepts and extend multiple modules at once', () => {
  198. const A = class {}
  199. const B = class {}
  200. const C = class {}
  201. extend([A, B, C], {
  202. test() {
  203. this.prop = 'test'
  204. return this
  205. }
  206. })
  207. expect(typeof A.prototype.test).toBe('function')
  208. expect(new A().test().prop).toBe('test')
  209. expect(typeof B.prototype.test).toBe('function')
  210. expect(new B().test().prop).toBe('test')
  211. expect(typeof C.prototype.test).toBe('function')
  212. expect(new C().test().prop).toBe('test')
  213. })
  214. })
  215. describe('wrapWithAttrCheck()', () => {
  216. it('wraps a function so that it calls an attr function if an object is passed', () => {
  217. const attrSpy = createSpy('attr')
  218. const A = class {}
  219. extend(A, {
  220. test: wrapWithAttrCheck(function () {
  221. this.prop = 'test'
  222. return this
  223. }),
  224. attr: attrSpy
  225. })
  226. const obj = {}
  227. expect(new A().test().prop).toBe('test')
  228. expect(attrSpy).not.toHaveBeenCalled()
  229. new A().test(obj)
  230. expect(attrSpy).toHaveBeenCalledWith(obj)
  231. })
  232. })
  233. })