api-ipc-renderer-spec.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. 'use strict'
  2. const assert = require('assert')
  3. const http = require('http')
  4. const path = require('path')
  5. const {closeWindow} = require('./window-helpers')
  6. const {ipcRenderer, remote} = require('electron')
  7. const {ipcMain, webContents, BrowserWindow} = remote
  8. describe('ipc renderer module', () => {
  9. const fixtures = path.join(__dirname, 'fixtures')
  10. let w = null
  11. afterEach(() => closeWindow(w).then(() => { w = null }))
  12. describe('ipc.sender.send', () => {
  13. it('should work when sending an object containing id property', (done) => {
  14. const obj = {
  15. id: 1,
  16. name: 'ly'
  17. }
  18. ipcRenderer.once('message', function (event, message) {
  19. assert.deepEqual(message, obj)
  20. done()
  21. })
  22. ipcRenderer.send('message', obj)
  23. })
  24. it('can send instances of Date', (done) => {
  25. const currentDate = new Date()
  26. ipcRenderer.once('message', function (event, value) {
  27. assert.equal(value, currentDate.toISOString())
  28. done()
  29. })
  30. ipcRenderer.send('message', currentDate)
  31. })
  32. it('can send instances of Buffer', (done) => {
  33. const buffer = Buffer.from('hello')
  34. ipcRenderer.once('message', function (event, message) {
  35. assert.ok(buffer.equals(message))
  36. done()
  37. })
  38. ipcRenderer.send('message', buffer)
  39. })
  40. it('can send objects with DOM class prototypes', (done) => {
  41. ipcRenderer.once('message', function (event, value) {
  42. assert.equal(value.protocol, 'file:')
  43. assert.equal(value.hostname, '')
  44. done()
  45. })
  46. ipcRenderer.send('message', document.location)
  47. })
  48. it('can send Electron API objects', (done) => {
  49. const webContents = remote.getCurrentWebContents()
  50. ipcRenderer.once('message', function (event, value) {
  51. assert.deepEqual(value.browserWindowOptions, webContents.browserWindowOptions)
  52. done()
  53. })
  54. ipcRenderer.send('message', webContents)
  55. })
  56. it('does not crash on external objects (regression)', (done) => {
  57. const request = http.request({port: 5000, hostname: '127.0.0.1', method: 'GET', path: '/'})
  58. const stream = request.agent.sockets['127.0.0.1:5000:'][0]._handle._externalStream
  59. request.on('error', () => {})
  60. ipcRenderer.once('message', function (event, requestValue, externalStreamValue) {
  61. assert.equal(requestValue.method, 'GET')
  62. assert.equal(requestValue.path, '/')
  63. assert.equal(externalStreamValue, null)
  64. done()
  65. })
  66. ipcRenderer.send('message', request, stream)
  67. })
  68. it('can send objects that both reference the same object', (done) => {
  69. const child = {hello: 'world'}
  70. const foo = {name: 'foo', child: child}
  71. const bar = {name: 'bar', child: child}
  72. const array = [foo, bar]
  73. ipcRenderer.once('message', function (event, arrayValue, fooValue, barValue, childValue) {
  74. assert.deepEqual(arrayValue, array)
  75. assert.deepEqual(fooValue, foo)
  76. assert.deepEqual(barValue, bar)
  77. assert.deepEqual(childValue, child)
  78. done()
  79. })
  80. ipcRenderer.send('message', array, foo, bar, child)
  81. })
  82. it('inserts null for cyclic references', (done) => {
  83. const array = [5]
  84. array.push(array)
  85. const child = {hello: 'world'}
  86. child.child = child
  87. ipcRenderer.once('message', function (event, arrayValue, childValue) {
  88. assert.equal(arrayValue[0], 5)
  89. assert.equal(arrayValue[1], null)
  90. assert.equal(childValue.hello, 'world')
  91. assert.equal(childValue.child, null)
  92. done()
  93. })
  94. ipcRenderer.send('message', array, child)
  95. })
  96. })
  97. describe('ipc.sendSync', () => {
  98. afterEach(() => {
  99. ipcMain.removeAllListeners('send-sync-message')
  100. })
  101. it('can be replied by setting event.returnValue', () => {
  102. const msg = ipcRenderer.sendSync('echo', 'test')
  103. assert.equal(msg, 'test')
  104. })
  105. })
  106. describe('ipcRenderer.sendTo', () => {
  107. let contents = null
  108. beforeEach(() => { contents = webContents.create({}) })
  109. afterEach(() => {
  110. ipcRenderer.removeAllListeners('pong')
  111. contents.destroy()
  112. contents = null
  113. })
  114. it('sends message to WebContents', (done) => {
  115. const webContentsId = remote.getCurrentWebContents().id
  116. ipcRenderer.once('pong', function (event, id) {
  117. assert.equal(webContentsId, id)
  118. done()
  119. })
  120. contents.once('did-finish-load', () => {
  121. ipcRenderer.sendTo(contents.id, 'ping', webContentsId)
  122. })
  123. contents.loadURL(`file://${path.join(fixtures, 'pages', 'ping-pong.html')}`)
  124. })
  125. })
  126. describe('remote listeners', () => {
  127. it('detaches listeners subscribed to destroyed renderers, and shows a warning', (done) => {
  128. w = new BrowserWindow({ show: false })
  129. w.webContents.once('did-finish-load', () => {
  130. w.webContents.once('did-finish-load', () => {
  131. const expectedMessage = [
  132. 'Attempting to call a function in a renderer window that has been closed or released.',
  133. 'Function provided here: remote-event-handler.html:11:33',
  134. 'Remote event names: remote-handler, other-remote-handler'
  135. ].join('\n')
  136. const results = ipcRenderer.sendSync('try-emit-web-contents-event', w.webContents.id, 'remote-handler')
  137. assert.deepEqual(results, {
  138. warningMessage: expectedMessage,
  139. listenerCountBefore: 2,
  140. listenerCountAfter: 1
  141. })
  142. done()
  143. })
  144. w.webContents.reload()
  145. })
  146. w.loadURL(`file://${path.join(fixtures, 'api', 'remote-event-handler.html')}`)
  147. })
  148. })
  149. it('throws an error when removing all the listeners', () => {
  150. ipcRenderer.on('test-event', () => {})
  151. assert.equal(ipcRenderer.listenerCount('test-event'), 1)
  152. assert.throws(() => {
  153. ipcRenderer.removeAllListeners()
  154. }, /Removing all listeners from ipcRenderer will make Electron internals stop working/)
  155. ipcRenderer.removeAllListeners('test-event')
  156. assert.equal(ipcRenderer.listenerCount('test-event'), 0)
  157. })
  158. })