api-ipc-main-spec.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. 'use strict'
  2. const chai = require('chai')
  3. const dirtyChai = require('dirty-chai')
  4. const path = require('path')
  5. const cp = require('child_process')
  6. const { closeWindow } = require('./window-helpers')
  7. const { emittedOnce } = require('./events-helpers')
  8. const { expect } = chai
  9. chai.use(dirtyChai)
  10. const { remote } = require('electron')
  11. const { ipcMain, BrowserWindow } = remote
  12. describe('ipc main module', () => {
  13. const fixtures = path.join(__dirname, 'fixtures')
  14. let w = null
  15. afterEach(() => closeWindow(w).then(() => { w = null }))
  16. describe('ipc.sendSync', () => {
  17. afterEach(() => { ipcMain.removeAllListeners('send-sync-message') })
  18. it('does not crash when reply is not sent and browser is destroyed', (done) => {
  19. w = new BrowserWindow({
  20. show: false,
  21. webPreferences: {
  22. nodeIntegration: true
  23. }
  24. })
  25. ipcMain.once('send-sync-message', (event) => {
  26. event.returnValue = null
  27. done()
  28. })
  29. w.loadFile(path.join(fixtures, 'api', 'send-sync-message.html'))
  30. })
  31. it('does not crash when reply is sent by multiple listeners', (done) => {
  32. w = new BrowserWindow({
  33. show: false,
  34. webPreferences: {
  35. nodeIntegration: true
  36. }
  37. })
  38. ipcMain.on('send-sync-message', (event) => {
  39. event.returnValue = null
  40. })
  41. ipcMain.on('send-sync-message', (event) => {
  42. event.returnValue = null
  43. done()
  44. })
  45. w.loadFile(path.join(fixtures, 'api', 'send-sync-message.html'))
  46. })
  47. })
  48. describe('remote listeners', () => {
  49. it('can be added and removed correctly', () => {
  50. w = new BrowserWindow({ show: false })
  51. const listener = () => {}
  52. w.on('test', listener)
  53. expect(w.listenerCount('test')).to.equal(1)
  54. w.removeListener('test', listener)
  55. expect(w.listenerCount('test')).to.equal(0)
  56. })
  57. })
  58. describe('remote objects registry', () => {
  59. it('does not dereference until the render view is deleted (regression)', (done) => {
  60. w = new BrowserWindow({
  61. show: false,
  62. webPreferences: {
  63. nodeIntegration: true
  64. }
  65. })
  66. ipcMain.once('error-message', (event, message) => {
  67. const correctMsgStart = message.startsWith('Cannot call method \'getURL\' on missing remote object')
  68. expect(correctMsgStart).to.be.true()
  69. done()
  70. })
  71. w.loadFile(path.join(fixtures, 'api', 'render-view-deleted.html'))
  72. })
  73. })
  74. describe('ipcMain.on', () => {
  75. it('is not used for internals', async () => {
  76. const appPath = path.join(__dirname, 'fixtures', 'api', 'ipc-main-listeners')
  77. const electronPath = remote.getGlobal('process').execPath
  78. const appProcess = cp.spawn(electronPath, [appPath])
  79. let output = ''
  80. appProcess.stdout.on('data', (data) => { output += data })
  81. await emittedOnce(appProcess.stdout, 'end')
  82. output = JSON.parse(output)
  83. expect(output).to.deep.equal(['error'])
  84. })
  85. })
  86. })