backdrop.spec.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. import Backdrop from '../../../src/util/backdrop.js'
  2. import { getTransitionDurationFromElement } from '../../../src/util/index.js'
  3. import { clearFixture, getFixture } from '../../helpers/fixture.js'
  4. const CLASS_BACKDROP = '.modal-backdrop'
  5. const CLASS_NAME_FADE = 'fade'
  6. const CLASS_NAME_SHOW = 'show'
  7. describe('Backdrop', () => {
  8. let fixtureEl
  9. beforeAll(() => {
  10. fixtureEl = getFixture()
  11. })
  12. afterEach(() => {
  13. clearFixture()
  14. const list = document.querySelectorAll(CLASS_BACKDROP)
  15. for (const el of list) {
  16. el.remove()
  17. }
  18. })
  19. describe('show', () => {
  20. it('should append the backdrop html once on show and include the "show" class if it is "shown"', () => {
  21. return new Promise(resolve => {
  22. const instance = new Backdrop({
  23. isVisible: true,
  24. isAnimated: false
  25. })
  26. const getElements = () => document.querySelectorAll(CLASS_BACKDROP)
  27. expect(getElements()).toHaveSize(0)
  28. instance.show()
  29. instance.show(() => {
  30. expect(getElements()).toHaveSize(1)
  31. for (const el of getElements()) {
  32. expect(el).toHaveClass(CLASS_NAME_SHOW)
  33. }
  34. resolve()
  35. })
  36. })
  37. })
  38. it('should not append the backdrop html if it is not "shown"', () => {
  39. return new Promise(resolve => {
  40. const instance = new Backdrop({
  41. isVisible: false,
  42. isAnimated: true
  43. })
  44. const getElements = () => document.querySelectorAll(CLASS_BACKDROP)
  45. expect(getElements()).toHaveSize(0)
  46. instance.show(() => {
  47. expect(getElements()).toHaveSize(0)
  48. resolve()
  49. })
  50. })
  51. })
  52. it('should append the backdrop html once and include the "fade" class if it is "shown" and "animated"', () => {
  53. return new Promise(resolve => {
  54. const instance = new Backdrop({
  55. isVisible: true,
  56. isAnimated: true
  57. })
  58. const getElements = () => document.querySelectorAll(CLASS_BACKDROP)
  59. expect(getElements()).toHaveSize(0)
  60. instance.show(() => {
  61. expect(getElements()).toHaveSize(1)
  62. for (const el of getElements()) {
  63. expect(el).toHaveClass(CLASS_NAME_FADE)
  64. }
  65. resolve()
  66. })
  67. })
  68. })
  69. })
  70. describe('hide', () => {
  71. it('should remove the backdrop html', () => {
  72. return new Promise(resolve => {
  73. const instance = new Backdrop({
  74. isVisible: true,
  75. isAnimated: true
  76. })
  77. const getElements = () => document.body.querySelectorAll(CLASS_BACKDROP)
  78. expect(getElements()).toHaveSize(0)
  79. instance.show(() => {
  80. expect(getElements()).toHaveSize(1)
  81. instance.hide(() => {
  82. expect(getElements()).toHaveSize(0)
  83. resolve()
  84. })
  85. })
  86. })
  87. })
  88. it('should remove the "show" class', () => {
  89. return new Promise(resolve => {
  90. const instance = new Backdrop({
  91. isVisible: true,
  92. isAnimated: true
  93. })
  94. const elem = instance._getElement()
  95. instance.show()
  96. instance.hide(() => {
  97. expect(elem).not.toHaveClass(CLASS_NAME_SHOW)
  98. resolve()
  99. })
  100. })
  101. })
  102. it('should not try to remove Node on remove method if it is not "shown"', () => {
  103. return new Promise(resolve => {
  104. const instance = new Backdrop({
  105. isVisible: false,
  106. isAnimated: true
  107. })
  108. const getElements = () => document.querySelectorAll(CLASS_BACKDROP)
  109. const spy = spyOn(instance, 'dispose').and.callThrough()
  110. expect(getElements()).toHaveSize(0)
  111. expect(instance._isAppended).toBeFalse()
  112. instance.show(() => {
  113. instance.hide(() => {
  114. expect(getElements()).toHaveSize(0)
  115. expect(spy).not.toHaveBeenCalled()
  116. expect(instance._isAppended).toBeFalse()
  117. resolve()
  118. })
  119. })
  120. })
  121. })
  122. it('should not error if the backdrop no longer has a parent', () => {
  123. return new Promise(resolve => {
  124. fixtureEl.innerHTML = '<div id="wrapper"></div>'
  125. const wrapper = fixtureEl.querySelector('#wrapper')
  126. const instance = new Backdrop({
  127. isVisible: true,
  128. isAnimated: true,
  129. rootElement: wrapper
  130. })
  131. const getElements = () => document.querySelectorAll(CLASS_BACKDROP)
  132. instance.show(() => {
  133. wrapper.remove()
  134. instance.hide(() => {
  135. expect(getElements()).toHaveSize(0)
  136. resolve()
  137. })
  138. })
  139. })
  140. })
  141. })
  142. describe('click callback', () => {
  143. it('should execute callback on click', () => {
  144. return new Promise(resolve => {
  145. const spy = jasmine.createSpy('spy')
  146. const instance = new Backdrop({
  147. isVisible: true,
  148. isAnimated: false,
  149. clickCallback: () => spy()
  150. })
  151. const endTest = () => {
  152. setTimeout(() => {
  153. expect(spy).toHaveBeenCalled()
  154. resolve()
  155. }, 10)
  156. }
  157. instance.show(() => {
  158. const clickEvent = new Event('mousedown', { bubbles: true, cancelable: true })
  159. document.querySelector(CLASS_BACKDROP).dispatchEvent(clickEvent)
  160. endTest()
  161. })
  162. })
  163. })
  164. describe('animation callbacks', () => {
  165. it('should show and hide backdrop after counting transition duration if it is animated', () => {
  166. return new Promise(resolve => {
  167. const instance = new Backdrop({
  168. isVisible: true,
  169. isAnimated: true
  170. })
  171. const spy2 = jasmine.createSpy('spy2')
  172. const execDone = () => {
  173. setTimeout(() => {
  174. expect(spy2).toHaveBeenCalledTimes(2)
  175. resolve()
  176. }, 10)
  177. }
  178. instance.show(spy2)
  179. instance.hide(() => {
  180. spy2()
  181. execDone()
  182. })
  183. expect(spy2).not.toHaveBeenCalled()
  184. })
  185. })
  186. it('should show and hide backdrop without a delay if it is not animated', () => {
  187. return new Promise(resolve => {
  188. const spy = jasmine.createSpy('spy', getTransitionDurationFromElement)
  189. const instance = new Backdrop({
  190. isVisible: true,
  191. isAnimated: false
  192. })
  193. const spy2 = jasmine.createSpy('spy2')
  194. instance.show(spy2)
  195. instance.hide(spy2)
  196. setTimeout(() => {
  197. expect(spy2).toHaveBeenCalled()
  198. expect(spy).not.toHaveBeenCalled()
  199. resolve()
  200. }, 10)
  201. })
  202. })
  203. it('should not call delay callbacks if it is not "shown"', () => {
  204. return new Promise(resolve => {
  205. const instance = new Backdrop({
  206. isVisible: false,
  207. isAnimated: true
  208. })
  209. const spy = jasmine.createSpy('spy', getTransitionDurationFromElement)
  210. instance.show()
  211. instance.hide(() => {
  212. expect(spy).not.toHaveBeenCalled()
  213. resolve()
  214. })
  215. })
  216. })
  217. })
  218. describe('Config', () => {
  219. describe('rootElement initialization', () => {
  220. it('should be appended on "document.body" by default', () => {
  221. return new Promise(resolve => {
  222. const instance = new Backdrop({
  223. isVisible: true
  224. })
  225. const getElement = () => document.querySelector(CLASS_BACKDROP)
  226. instance.show(() => {
  227. expect(getElement().parentElement).toEqual(document.body)
  228. resolve()
  229. })
  230. })
  231. })
  232. it('should find the rootElement if passed as a string', () => {
  233. return new Promise(resolve => {
  234. const instance = new Backdrop({
  235. isVisible: true,
  236. rootElement: 'body'
  237. })
  238. const getElement = () => document.querySelector(CLASS_BACKDROP)
  239. instance.show(() => {
  240. expect(getElement().parentElement).toEqual(document.body)
  241. resolve()
  242. })
  243. })
  244. })
  245. it('should be appended on any element given by the proper config', () => {
  246. return new Promise(resolve => {
  247. fixtureEl.innerHTML = '<div id="wrapper"></div>'
  248. const wrapper = fixtureEl.querySelector('#wrapper')
  249. const instance = new Backdrop({
  250. isVisible: true,
  251. rootElement: wrapper
  252. })
  253. const getElement = () => document.querySelector(CLASS_BACKDROP)
  254. instance.show(() => {
  255. expect(getElement().parentElement).toEqual(wrapper)
  256. resolve()
  257. })
  258. })
  259. })
  260. })
  261. describe('ClassName', () => {
  262. it('should allow configuring className', () => {
  263. return new Promise(resolve => {
  264. const instance = new Backdrop({
  265. isVisible: true,
  266. className: 'foo'
  267. })
  268. const getElement = () => document.querySelector('.foo')
  269. instance.show(() => {
  270. expect(getElement()).toEqual(instance._getElement())
  271. instance.dispose()
  272. resolve()
  273. })
  274. })
  275. })
  276. })
  277. })
  278. })
  279. })