api-browser-view-spec.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. 'use strict'
  2. const assert = require('assert')
  3. const chai = require('chai')
  4. const ChildProcess = require('child_process')
  5. const dirtyChai = require('dirty-chai')
  6. const path = require('path')
  7. const { emittedOnce } = require('./events-helpers')
  8. const { closeWindow } = require('./window-helpers')
  9. const { remote } = require('electron')
  10. const { BrowserView, BrowserWindow } = remote
  11. const { expect } = chai
  12. chai.use(dirtyChai)
  13. describe('BrowserView module', () => {
  14. const fixtures = path.resolve(__dirname, 'fixtures')
  15. let w = null
  16. let view = null
  17. beforeEach(() => {
  18. w = new BrowserWindow({
  19. show: false,
  20. width: 400,
  21. height: 400,
  22. webPreferences: {
  23. backgroundThrottling: false
  24. }
  25. })
  26. })
  27. afterEach(() => {
  28. if (view) {
  29. view.destroy()
  30. view = null
  31. }
  32. return closeWindow(w).then(() => { w = null })
  33. })
  34. describe('BrowserView.destroy()', () => {
  35. it('does not throw', () => {
  36. view = new BrowserView()
  37. view.destroy()
  38. })
  39. })
  40. describe('BrowserView.isDestroyed()', () => {
  41. it('returns correct value', () => {
  42. view = new BrowserView()
  43. expect(view.isDestroyed()).to.be.false()
  44. view.destroy()
  45. expect(view.isDestroyed()).to.be.true()
  46. })
  47. })
  48. describe('BrowserView.setBackgroundColor()', () => {
  49. it('does not throw for valid args', () => {
  50. view = new BrowserView()
  51. view.setBackgroundColor('#000')
  52. })
  53. it('throws for invalid args', () => {
  54. view = new BrowserView()
  55. expect(() => {
  56. view.setBackgroundColor(null)
  57. }).to.throw(/conversion failure/)
  58. })
  59. })
  60. describe('BrowserView.setAutoResize()', () => {
  61. it('does not throw for valid args', () => {
  62. view = new BrowserView()
  63. view.setAutoResize({})
  64. view.setAutoResize({ width: true, height: false })
  65. })
  66. it('throws for invalid args', () => {
  67. view = new BrowserView()
  68. expect(() => {
  69. view.setAutoResize(null)
  70. }).to.throw(/conversion failure/)
  71. })
  72. })
  73. describe('BrowserView.setBounds()', () => {
  74. it('does not throw for valid args', () => {
  75. view = new BrowserView()
  76. view.setBounds({ x: 0, y: 0, width: 1, height: 1 })
  77. })
  78. it('throws for invalid args', () => {
  79. view = new BrowserView()
  80. expect(() => {
  81. view.setBounds(null)
  82. }).to.throw(/conversion failure/)
  83. expect(() => {
  84. view.setBounds({})
  85. }).to.throw(/conversion failure/)
  86. })
  87. })
  88. describe('BrowserWindow.setBrowserView()', () => {
  89. it('does not throw for valid args', () => {
  90. view = new BrowserView()
  91. w.setBrowserView(view)
  92. })
  93. it('does not throw if called multiple times with same view', () => {
  94. view = new BrowserView()
  95. w.setBrowserView(view)
  96. w.setBrowserView(view)
  97. w.setBrowserView(view)
  98. })
  99. })
  100. describe('BrowserWindow.getBrowserView()', () => {
  101. it('returns the set view', () => {
  102. view = new BrowserView()
  103. w.setBrowserView(view)
  104. expect(view.id).to.not.be.null()
  105. const view2 = w.getBrowserView()
  106. expect(view2.webContents.id).to.equal(view.webContents.id)
  107. })
  108. it('returns null if none is set', () => {
  109. const view = w.getBrowserView()
  110. expect(view).to.be.null()
  111. })
  112. })
  113. describe('BrowserWindow.addBrowserView()', () => {
  114. it('does not throw for valid args', () => {
  115. let view1 = new BrowserView()
  116. w.addBrowserView(view1)
  117. let view2 = new BrowserView()
  118. w.addBrowserView(view2)
  119. view1.destroy()
  120. view1 = null
  121. view2.destroy()
  122. view2 = null
  123. })
  124. it('does not throw if called multiple times with same view', () => {
  125. view = new BrowserView()
  126. w.addBrowserView(view)
  127. w.addBrowserView(view)
  128. w.addBrowserView(view)
  129. })
  130. })
  131. describe('BrowserWindow.removeBrowserView()', () => {
  132. it('does not throw if called multiple times with same view', () => {
  133. view = new BrowserView()
  134. w.addBrowserView(view)
  135. w.removeBrowserView(view)
  136. w.removeBrowserView(view)
  137. })
  138. })
  139. describe('BrowserWindow.getBrowserViews()', () => {
  140. it('returns same views as was added', () => {
  141. let view1 = new BrowserView()
  142. w.addBrowserView(view1)
  143. let view2 = new BrowserView()
  144. w.addBrowserView(view2)
  145. expect(view1.id).to.be.not.null()
  146. const views = w.getBrowserViews()
  147. expect(views.length).to.equal(2)
  148. expect(views[0].webContents.id).to.equal(view1.webContents.id)
  149. expect(views[1].webContents.id).to.equal(view2.webContents.id)
  150. view1.destroy()
  151. view1 = null
  152. view2.destroy()
  153. view2 = null
  154. })
  155. })
  156. describe('BrowserView.webContents.getOwnerBrowserWindow()', () => {
  157. it('points to owning window', () => {
  158. view = new BrowserView()
  159. expect(view.webContents.getOwnerBrowserWindow()).to.be.null()
  160. w.setBrowserView(view)
  161. expect(view.webContents.getOwnerBrowserWindow()).to.equal(w)
  162. w.setBrowserView(null)
  163. expect(view.webContents.getOwnerBrowserWindow()).to.be.null()
  164. })
  165. })
  166. describe('BrowserView.fromId()', () => {
  167. it('returns the view with given id', () => {
  168. view = new BrowserView()
  169. w.setBrowserView(view)
  170. expect(view.id).to.not.be.null()
  171. const view2 = BrowserView.fromId(view.id)
  172. expect(view2.webContents.id).to.equal(view.webContents.id)
  173. })
  174. })
  175. describe('BrowserView.fromWebContents()', () => {
  176. it('returns the view with given id', () => {
  177. view = new BrowserView()
  178. w.setBrowserView(view)
  179. expect(view.id).to.not.be.null()
  180. const view2 = BrowserView.fromWebContents(view.webContents)
  181. expect(view2.webContents.id).to.equal(view.webContents.id)
  182. })
  183. })
  184. describe('BrowserView.getAllViews()', () => {
  185. it('returns all views', () => {
  186. view = new BrowserView()
  187. w.setBrowserView(view)
  188. expect(view.id).to.not.be.null()
  189. const views = BrowserView.getAllViews()
  190. expect(views).to.be.an('array').that.has.lengthOf(1)
  191. expect(views[0].webContents.id).to.equal(view.webContents.id)
  192. })
  193. })
  194. describe('new BrowserView()', () => {
  195. it('does not crash on exit', async () => {
  196. const appPath = path.join(fixtures, 'api', 'leak-exit-browserview.js')
  197. const electronPath = remote.getGlobal('process').execPath
  198. const appProcess = ChildProcess.spawn(electronPath, [appPath])
  199. const [code] = await emittedOnce(appProcess, 'close')
  200. expect(code).to.equal(0)
  201. })
  202. })
  203. describe('window.open()', () => {
  204. it('works in BrowserView', (done) => {
  205. view = new BrowserView()
  206. w.setBrowserView(view)
  207. view.webContents.once('new-window', (e, url, frameName, disposition, options, additionalFeatures) => {
  208. e.preventDefault()
  209. assert.strictEqual(url, 'http://host/')
  210. assert.strictEqual(frameName, 'host')
  211. assert.strictEqual(additionalFeatures[0], 'this-is-not-a-standard-feature')
  212. done()
  213. })
  214. view.webContents.loadFile(path.join(fixtures, 'pages', 'window-open.html'))
  215. })
  216. })
  217. })