├── .eslintrc.json ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── appveyor.yml ├── docs ├── ipc-main.md └── ipc-renderer.md ├── examples ├── basic │ ├── index.html │ ├── main.js │ └── package.json └── multi-version │ ├── bar │ ├── index.js │ └── package.json │ ├── foo │ ├── index.js │ └── package.json │ ├── index.html │ ├── main.js │ └── package.json ├── index.js ├── lib ├── common.js ├── ipc-main.js └── ipc-renderer.js ├── package.json └── test ├── fixtures ├── app-main2all-exclude-self │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2all │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2main-reply │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2main │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2win-reply-a-user-error │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2win-reply-cancel-request │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2win-reply-error-invalid-first-arg │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2win-reply-error-win-destroyed │ ├── index.html │ ├── index2.html │ ├── main.js │ └── package.json ├── app-main2win-reply-more-than-once │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2win-reply-nested │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2win-reply-timeout │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2win-reply │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2win │ ├── index.html │ ├── main.js │ └── package.json ├── app-main2wins │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2all-exclude-self │ ├── index.html │ ├── main.js │ ├── package.json │ └── send.html ├── app-win2all │ ├── index.html │ ├── main.js │ ├── package.json │ └── send.html ├── app-win2main-reply-a-user-error │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2main-reply-cancel-request │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2main-reply-error-no-callback │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2main-reply-error-win-destroyed │ ├── index.html │ ├── index2.html │ ├── main.js │ └── package.json ├── app-win2main-reply-invalid-first-arg │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2main-reply-more-than-once │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2main-reply-nested │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2main-reply-timeout │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2main-reply │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2main │ ├── index.html │ ├── main.js │ └── package.json ├── app-win2wins-exclude-self │ ├── index.html │ ├── main.js │ ├── package.json │ └── send.html └── app-win2wins │ ├── index.html │ ├── main.js │ ├── package.json │ └── send.html ├── send-to-all.spec.js ├── send-to-main-reply.spec.js ├── send-to-main.spec.js ├── send-to-win-reply.spec.js ├── send-to-win.spec.js └── send-to-wins.spec.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "rules": { 4 | "comma-dangle": 0, 5 | "no-console": 0, 6 | "no-constant-condition": 0, 7 | "semi": 1 8 | }, 9 | "parserOptions": { 10 | "ecmaVersion": 6, 11 | "ecmaFeatures": { 12 | "jsx": true 13 | } 14 | }, 15 | "env": { 16 | "browser": true, 17 | "node": true, 18 | "es6": true, 19 | "mocha": true 20 | }, 21 | "plugins": [ 22 | ], 23 | "globals": { 24 | "deprecate": false, 25 | "helper": false, 26 | "tap": false, 27 | "unused": false 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # mac-osx files 2 | .DS_store 3 | profile 4 | 5 | # visual-studio files 6 | *.ncb *.sln 7 | *.suo 8 | *.vcproj.*.user 9 | *.pdb 10 | *.idb 11 | *.csproj 12 | *.csproj.user 13 | 14 | # visual-studio code 15 | .vscode/ 16 | 17 | # exvim files 18 | *.err 19 | *.exvim 20 | .exvim.*/ 21 | 22 | # webstorm 23 | .idea 24 | 25 | # log files 26 | *.log 27 | 28 | # project files 29 | node_modules/ 30 | bower_components/ 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | - osx 4 | 5 | language: node_js 6 | 7 | node_js: 8 | - "6" 9 | 10 | branches: 11 | only: 12 | - master 13 | 14 | cache: 15 | - directories: 16 | - node_modules 17 | 18 | install: 19 | - export DISPLAY=':99.0' 20 | - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & 21 | - npm install 22 | 23 | script: npm test 24 | 25 | notifications: 26 | email: false 27 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## CHANGELOG 2 | 3 | ### v1.3.3 4 | 5 | - Better warning message for version conflict (again). 6 | 7 | ### v1.3.2 8 | 9 | - Better warning message for version conflict. 10 | 11 | ### v1.3.1 12 | 13 | - Add version protection warning message. 14 | 15 | ### v1.3.0 16 | 17 | - Add version protection so that different versions of the `electorn-ipc-plus` can run in the same process. 18 | 19 | ### v1.2.3 20 | 21 | - Register window `closed` event in `app.on('browser-window-created')`. 22 | 23 | ### v1.2.2 24 | 25 | - Add `ipcPlus.internal` for internal use. 26 | 27 | ### v1.2.1 28 | 29 | - Fix window close will not clear caches in main process. 30 | 31 | ### v1.2.0 32 | 33 | - Window closed will force close all sessions relate with it in main process. 34 | 35 | ### v1.1.0 36 | 37 | - Allow user reply custom Error. 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2017 Johnny Wu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electron-ipc-plus 2 | 3 | [![Linux Build Status](https://travis-ci.org/electron-utils/electron-ipc-plus.svg?branch=master)](https://travis-ci.org/electron-utils/electron-ipc-plus) 4 | [![Windows Build status](https://ci.appveyor.com/api/projects/status/crnftwhvfxyldw75?svg=true)](https://ci.appveyor.com/project/jwu/electron-ipc-plus) 5 | [![Dependency Status](https://david-dm.org/electron-utils/electron-ipc-plus.svg)](https://david-dm.org/electron-utils/electron-ipc-plus) 6 | [![devDependency Status](https://david-dm.org/electron-utils/electron-ipc-plus/dev-status.svg)](https://david-dm.org/electron-utils/electron-ipc-plus#info=devDependencies) 7 | 8 | Improved IPC for Electron 9 | 10 | ## Features 11 | 12 | - Enhance IPC Programming Experience 13 | - Allow sending ipc message to specific window 14 | - Allow sending ipc request and waiting for the reply in callback function 15 | 16 | ## Install 17 | 18 | ```bash 19 | npm install --save electron-ipc-plus 20 | ``` 21 | 22 | ## Run The Example 23 | 24 | ```bash 25 | npm start examples/${name} 26 | ``` 27 | 28 | ## Usage 29 | 30 | ### Send request from main process to renderer process and wait for reply. 31 | 32 | **main process** 33 | 34 | ```javascript 35 | const ipcPlusM = require('electron-ipc-plus'); 36 | 37 | ipcPlusM.sendToWin(browserWin, 'app:say-hello', 'hello renderer process!', (err, message) => { 38 | console.log(`renderer replied: ${message}`); 39 | }); 40 | ``` 41 | 42 | **renderer process** 43 | 44 | ```javascript 45 | const ipcPlusR = require('electron-ipc-plus'); 46 | 47 | ipcPlusR.on('app:say-hello', (event, message) => { 48 | console.log(`main process said: ${message}`); 49 | 50 | setTimeout(() => { 51 | event.reply(null, 'hi main process!'); 52 | }, 500); 53 | }); 54 | ``` 55 | 56 | ### Send request from renderer process to main process and wait for reply. 57 | 58 | **renderer process** 59 | 60 | ```javascript 61 | const ipcPlusR = require('electron-ipc-plus'); 62 | 63 | ipcPlusR.sendToMain('app:say-hello', 'hello main process!', (err, message) => { 64 | console.log(`main replied: ${message}`); 65 | }); 66 | ``` 67 | 68 | **main process** 69 | 70 | ```javascript 71 | const ipcPlusM = require('electron-ipc-plus'); 72 | 73 | ipcPlusM.on('app:say-hello', (event, message) => { 74 | console.log(`renderer process said: ${message}`); 75 | 76 | setTimeout(() => { 77 | event.reply(null, 'hi renderer process!'); 78 | }, 500); 79 | }); 80 | ``` 81 | 82 | ## FAQ 83 | 84 | ### How can I know if an IPC is waiting for reply? 85 | 86 | Just check if `event.reply` exists: 87 | 88 | ```javascript 89 | ipcMain.on('app:say-hello', (event, message) => { 90 | if ( event.reply ) { 91 | event.reply(null, 'hi renderer process!'); 92 | } 93 | }); 94 | ``` 95 | 96 | ### Can I reply a message for multiple times? 97 | 98 | Only the first reply will be handled, after that the session will be closed and the rest of replies will be ignored. 99 | 100 | ### What happen when the window closed and I still waiting the reply from it. 101 | 102 | An error with the code `'EWINCLOSED'` will be sent to your reply handler. 103 | 104 | ```javascript 105 | ipcPlus.sendToWin(win, 'app:say-hello', (err, message) => { 106 | if ( err && err.code === 'EWINCLOSED' ) { 107 | console.error('Window closed'); 108 | } 109 | }); 110 | ``` 111 | 112 | ### What happen when the reply is timed out. 113 | 114 | An error with the code `'ETIMEDOUT'` will be sent to your reply handler. 115 | 116 | ```javascript 117 | ipcPlus.sendToWin(win, 'app:say-hello', (err, message) => { 118 | if ( err && err.code === 'ETIMEDOUT' ) { 119 | console.error('Target failed to reply you: timedout for 100ms'); 120 | } 121 | }, 100); 122 | ``` 123 | 124 | ## Known Issues 125 | 126 | ### ipcPlus.sendToWin could leave wild sessions in main process when the window reload. 127 | 128 | I try to solve this problem by the code below: 129 | 130 | ```javascript 131 | app.on('browser-window-created', (event, browserWin) => { 132 | // close all session once the window closed 133 | browserWin.webContents.once('did-navigate', () => { 134 | _closeAllSessionsInWin(browserWin); 135 | }); 136 | }); 137 | ``` 138 | 139 | The problem is 'did-navigate' will be triggerred at the first time we open the window and I disable the above solution and leave this to user. 140 | Currently the best way to solve it is wrapping your own reload function, and manually close all sessions in that wrapped function. 141 | 142 | ### Different versions of electron-ipc-plus. 143 | 144 | When running an Electron app that has several modules depends on different version of `electron-ipc-plus`, 145 | we will receive a warning message. 146 | 147 | ## API Reference 148 | 149 | - [Module: ipcPlus (main process)](docs/ipc-main.md) 150 | - [Module: ipcPlus (renderer process)](docs/ipc-renderer.md) 151 | 152 | ## License 153 | 154 | MIT © 2017 Johnny Wu 155 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | build: off 2 | 3 | os: unstable 4 | 5 | platform: 6 | - x86 7 | - x64 8 | 9 | branches: 10 | only: 11 | - master 12 | 13 | skip_tags: true 14 | 15 | environment: 16 | nodejs_version: "6" 17 | 18 | cache: 19 | - node_modules -> package.json 20 | 21 | install: 22 | - ps: Install-Product node $env:nodejs_version 23 | - npm install npm 24 | - .\node_modules\.bin\npm install 25 | 26 | test_script: 27 | - node --version 28 | - .\node_modules\.bin\npm --version 29 | - .\node_modules\.bin\npm test 30 | -------------------------------------------------------------------------------- /docs/ipc-main.md: -------------------------------------------------------------------------------- 1 | 2 | # Module: ipcPlus (main process) 3 | 4 | ## Methods 5 | 6 | ### ipcPlusM.option(opts) 7 | 8 | - `opts` object 9 | - `excludeSelf` boolean - exclude send ipc message to main process when calling `ipcPlusM.sendToAll`. 10 | 11 | Ipc option used in `ipcPlusM.sendToAll` and `ipcPlusM.sendToWins`. 12 | 13 | ### ipcPlusM.sendToAll(message[, ...args, option]) 14 | 15 | - `message` string - Ipc message. 16 | - `...args` ... - Whatever arguments the message needs. 17 | - `option` object - You can indicate the last argument as an IPC option by `ipcPlusM.option({...})`. 18 | 19 | Send `message` with `...args` to all opened window and to main process asynchronously. 20 | 21 | **NOTE** 22 | 23 | This is a broadcast method, it will not recieve callback. 24 | 25 | ### ipcPlusM.sendToWins(message[, ...args, option]) 26 | 27 | - `message` string - Ipc message. 28 | - `...args` ... - Whatever arguments the message needs. 29 | - `option` object - You can indicate the last argument as an IPC option by `ipcPlusM.option({...})`. 30 | 31 | Send `message` with `...args` to all opened windows asynchronously. The renderer process can handle it by listening to the message through the `electron.ipcRenderer` or `ipcPlus` module. 32 | 33 | **NOTE** 34 | 35 | This is a broadcast method, it will not recieve callback. 36 | 37 | Example: 38 | 39 | **Send IPC message (main process)** 40 | 41 | ```javascript 42 | const ipcPlusM = require('electron-ipc-plus'); 43 | 44 | ipcPlusM.sendToWins('foobar:say-hello', 'Hello World!'); 45 | ``` 46 | 47 | **Receive IPC message (renderer process)** 48 | 49 | ```html 50 | 51 | 52 | 59 | 60 | 61 | ``` 62 | 63 | ### ipcPlusM.sendToMain(message[, ...args, callback, timeout]) 64 | 65 | - `message` string - Ipc message. 66 | - `...args` ... - Whatever arguments the message needs. 67 | - `callback` function - You can specify a callback function to receive IPC reply at the last or the 2nd last argument. 68 | - `timeout` number - You can specify a timeout for the callback at the last argument. If no timeout specified, it will be 5000ms. 69 | 70 | Returns `number` - If we have callback function, a session ID will returned. 71 | 72 | Example: 73 | 74 | **Send IPC message (main process)** 75 | 76 | ```javascript 77 | const ipcPlusM = require('electron-ipc-plus'); 78 | 79 | ipcPlusM.sendToMain('foobar:say-hello', (err, msg) => { 80 | if ( err && err.code === 'ETIMEOUT' ) { 81 | console.error('Timeout for ipc message foobar:say-hello'); 82 | return; 83 | } 84 | 85 | console.log(`foobar replied: ${msg}`); 86 | }); 87 | ``` 88 | 89 | **Receive and Reply IPC message (main process)** 90 | 91 | ```javascript 92 | const {ipcMain} = require('electron'); 93 | 94 | ipcMain.on('foobar:say-hello', event => { 95 | event.reply(null, 'Hi'); 96 | }); 97 | ``` 98 | 99 | ### ipcPlusM.sendToWin(win, message[, ...args, callback, timeout]) 100 | 101 | - `win` BrowserWindow 102 | - `message` string - Ipc message. 103 | - `...args` ... - Whatever arguments the message needs. 104 | - `callback` function - You can specify a callback function to receive IPC reply at the last or the 2nd last argument. 105 | - `timeout` number - You can specify a timeout for the callback at the last argument. If no timeout specified, it will be 5000ms. 106 | 107 | Returns `number` - If we have callback function, a session ID will returned. 108 | 109 | Example: 110 | 111 | **Send IPC message (main process)** 112 | 113 | ```javascript 114 | const ipcPlusM = require('electron-ipc-plus'); 115 | 116 | ipcPlusM.sendToMain('foobar:say-hello', (err, msg) => { 117 | if ( err && err.code === 'ETIMEOUT' ) { 118 | console.error('Timeout for ipc message foobar:say-hello'); 119 | return; 120 | } 121 | 122 | console.log(`foobar replied: ${msg}`); 123 | }); 124 | ``` 125 | 126 | **Receive and Reply IPC message (renderer process)** 127 | 128 | ```javascript 129 | const {ipcRenderer} = require('electron'); 130 | 131 | ipcRenderer.on('foobar:say-hello', event => { 132 | event.reply(null, 'Hi'); 133 | }); 134 | ``` 135 | 136 | ### ipcPlusM.cancelRequest(sessionId) 137 | 138 | - `sessionId` number - The session ID. 139 | 140 | Cancel request sent to main or renderer process via `ipcPlusM.sendToMain` or `ipcPlusM.sendToWin`. 141 | 142 | ## Properties 143 | 144 | ### ipcPlusM.debug 145 | 146 | Turn on/off the debug information. No use in current version. -------------------------------------------------------------------------------- /docs/ipc-renderer.md: -------------------------------------------------------------------------------- 1 | # Module: ipcPlus (renderer process) 2 | 3 | ## Methods 4 | 5 | ### ipcPlusR.option(opts) 6 | 7 | - `opts` object 8 | - `excludeSelf` boolean - exclude send ipc message to main process when calling `ipcPlusR.sendToAll`. 9 | 10 | Ipc option used in `ipcPlusR.sendToAll` and `ipcPlusR.sendToWins`. 11 | 12 | ### ipcPlusR.sendToAll(message[, ...args, option]) 13 | 14 | - `message` string - Ipc message. 15 | - `...args` ... - Whatever arguments the message needs. 16 | - `option` object - You can indicate the last argument as an IPC option by `ipcPlusR.option({...})`. 17 | 18 | Send `message` with `...args` to all opened window and to main process asynchronously. 19 | 20 | **NOTE** 21 | 22 | This is a broadcast method, it will not recieve callback. 23 | 24 | ### ipcPlusR.sendToWins(message[, ...args, option]) 25 | 26 | - `message` string - Ipc message. 27 | - `...args` ... - Whatever arguments the message needs. 28 | - `option` object - You can indicate the last argument as an IPC option by `ipcPlusR.option({...})`. 29 | 30 | Send `message` with `...args` to all opened windows asynchronously. The renderer process can handle it by listening to the message through the `electron.ipcRenderer` or `ipcPlus` module. 31 | 32 | **NOTE** 33 | 34 | This is a broadcast method, it will not recieve callback. 35 | 36 | Example: 37 | 38 | **Send IPC message (renderer process)** 39 | 40 | ```javascript 41 | const ipcPlusR = require('electron-ipc-plus'); 42 | 43 | ipcPlusR.sendToWins('foobar:say-hello', 'Hello World!'); 44 | ``` 45 | 46 | ### ipcPlusR.sendToMainSync(message[, ...args]) 47 | 48 | - `message` string - Ipc message. 49 | - `...args` ... - Whatever arguments the message needs. 50 | 51 | Returns ...: Whatever returns from main process. 52 | 53 | Send `message` with `...args` to main process synchronously. (This is same as `electron.ipcRenderer.sendSync`). 54 | 55 | ### ipcPlusR.sendToMain(message[, ...args, callback, timeout]) 56 | 57 | - `message` string - Ipc message. 58 | - `...args` ... - Whatever arguments the message needs. 59 | - `callback` function - You can specify a callback function to receive IPC reply at the last or the 2nd last argument. 60 | - `timeout` number - You can specify a timeout for the callback at the last argument. If no timeout specified, it will be 5000ms. 61 | 62 | Returns `number` - If we have callback function, a session ID will returned. 63 | 64 | Example: 65 | 66 | **Send IPC message (renderer process)** 67 | 68 | ```javascript 69 | const ipcPlusR = require('electron-ipc-plus'); 70 | 71 | ipcPlusR.sendToMain('foobar:say-hello', (err, msg) => { 72 | if ( err && err.code === 'ETIMEOUT' ) { 73 | console.error('Timeout for ipc message foobar:say-hello'); 74 | return; 75 | } 76 | 77 | console.log(`foobar replied: ${msg}`); 78 | }); 79 | ``` 80 | 81 | **Receive and Reply IPC message (main process)** 82 | 83 | ```javascript 84 | const {ipcRenderer} = require('electron'); 85 | 86 | ipcRenderer.on('foobar:say-hello', event => { 87 | event.reply(null, 'Hi'); 88 | }); 89 | ``` 90 | 91 | ### ipcPlusR.cancelRequest(sessionId) 92 | 93 | - `sessionId` number - The session ID. 94 | 95 | Cancel request sent to main process via `ipcPlusR.sendToMain`. 96 | 97 | ## Properties 98 | 99 | ### ipcPlusR.debug 100 | 101 | Turn on/off the debug information. No use in current version. -------------------------------------------------------------------------------- /examples/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | main2all 6 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /examples/basic/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow, ipcMain} = require('electron'); 2 | const ipcPlus = require('../../index.js'); 3 | 4 | let win0, win1; 5 | 6 | app.on('ready', function () { 7 | // win0 8 | win0 = new BrowserWindow({ 9 | center: true, 10 | width: 400, 11 | height: 300, 12 | x: 100, 13 | y: 100, 14 | backgroundColor: '#09f', 15 | }); 16 | win0.loadURL('file://' + __dirname + '/index.html'); 17 | 18 | // win1 19 | win1 = new BrowserWindow({ 20 | center: true, 21 | width: 400, 22 | height: 300, 23 | x: 100 + 400 + 50, 24 | y: 100, 25 | backgroundColor: '#888', 26 | }); 27 | win1.loadURL('file://' + __dirname + '/index.html'); 28 | }); 29 | 30 | ipcPlus.on('app:main2all', (event, ...args) => { 31 | console.log(`received "app:main2all" at main process: ${args}`); 32 | }); 33 | 34 | ipcPlus.on('app:win2all', (event, ...args) => { 35 | console.log(`received "app:win2all" at main process: ${args}`); 36 | }); 37 | 38 | ipcPlus.on('app:win2main-reply', (event, ...args) => { 39 | console.log(`received "app:win2main-reply" at main process: ${args}, reply: bar after 500ms`); 40 | setTimeout(() => { 41 | event.reply(null, 'bar'); 42 | }, 500); 43 | }); 44 | 45 | ipcPlus.on('app:win2main-reply-error', (event, ...args) => { 46 | console.log(`received "app:win2main-reply-error" at main process: ${args}, reply: bar after 500ms`); 47 | setTimeout(() => { 48 | event.reply(new Error('Hello')); 49 | }, 500); 50 | }); 51 | 52 | // ==================== 53 | // handle buttons 54 | // ==================== 55 | 56 | ipcMain.on('btn:main2all', () => { 57 | console.log('send app:main2all foo, bar'); 58 | ipcPlus.sendToAll('app:main2all', 'foo', 'bar'); 59 | }); 60 | 61 | ipcMain.on('btn:main2all-exclude-self', () => { 62 | console.log('send app:main2all (exclude-self): foo, bar'); 63 | ipcPlus.sendToAll('app:main2all', 'foo', 'bar', ipcPlus.option({ 64 | excludeSelf: true 65 | })); 66 | }); 67 | 68 | ipcMain.on('btn:main2wins', () => { 69 | console.log('send app:main2wins foo, bar'); 70 | ipcPlus.sendToWins('app:main2wins', 'foo', 'bar'); 71 | }); 72 | 73 | ipcMain.on('btn:main2win', (event) => { 74 | console.log('send app:main2win foo, bar'); 75 | let win = BrowserWindow.fromWebContents( event.sender ); 76 | ipcPlus.sendToWin(win, 'app:main2win', 'foo', 'bar'); 77 | }); 78 | 79 | ipcMain.on('btn:main2win-reply', (event) => { 80 | let win = BrowserWindow.fromWebContents( event.sender ); 81 | console.log('send app:main2win-reply foo'); 82 | ipcPlus.sendToWin(win, 'app:main2win-reply', 'foo', (err, ...args) => { 83 | console.log(`received "app:main2win-reply" at main process: ${args}`); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /examples/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /examples/multi-version/bar/index.js: -------------------------------------------------------------------------------- 1 | const ipcPlus = require('electron-ipc-plus'); 2 | 3 | module.exports = { 4 | ipcPlus 5 | }; 6 | -------------------------------------------------------------------------------- /examples/multi-version/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0", 4 | "main": "main.js", 5 | "dependencies": { 6 | "electron-ipc-plus": "1.3.3" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/multi-version/foo/index.js: -------------------------------------------------------------------------------- 1 | const ipcPlus = require('electron-ipc-plus'); 2 | 3 | module.exports = { 4 | ipcPlus 5 | }; 6 | -------------------------------------------------------------------------------- /examples/multi-version/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "main": "main.js", 5 | "dependencies": { 6 | "electron-ipc-plus": "1.3.2" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/multi-version/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello 6 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/multi-version/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const foo = require('foo'); 3 | const bar = require('bar'); 4 | 5 | let win; 6 | 7 | app.on('ready', function () { 8 | // win 9 | win = new BrowserWindow({ 10 | center: true, 11 | width: 400, 12 | height: 300, 13 | x: 100, 14 | y: 100, 15 | backgroundColor: '#09f', 16 | }); 17 | win.loadURL('file://' + __dirname + '/index.html'); 18 | }); 19 | 20 | foo.ipcPlus.on('app:hello', event => { 21 | console.log('Received from renderer'); 22 | event.reply(null, 'Hello World'); 23 | }); 24 | -------------------------------------------------------------------------------- /examples/multi-version/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js", 5 | "dependencies": { 6 | "foo": "file:./foo", 7 | "bar": "file:./bar" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const platform = require('electron-platform'); 4 | 5 | let ipcPlus; 6 | 7 | if ( platform.isMainProcess ) { 8 | ipcPlus = require('./lib/ipc-main'); 9 | } else { 10 | ipcPlus = require('./lib/ipc-renderer'); 11 | } 12 | 13 | // ========================== 14 | // exports 15 | // ========================== 16 | 17 | module.exports = ipcPlus; 18 | -------------------------------------------------------------------------------- /lib/common.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let common = {}; 4 | 5 | common._wrapError = function (args) { 6 | if ( args.length === 0 ) { 7 | return true; 8 | } 9 | 10 | let first = args[0]; 11 | if ( first === null ) { 12 | return true; 13 | } 14 | 15 | if ( first instanceof Error ) { 16 | first = { 17 | __error__: true, 18 | stack: first.stack, 19 | message: first.message, 20 | // if this is a system error 21 | code: first.code, 22 | errno: first.errno, 23 | syscall: first.syscall, 24 | }; 25 | 26 | args[0] = first; 27 | return true; 28 | } 29 | 30 | // reply invalid-args error 31 | let err = new Error(); 32 | args.unshift({ 33 | __error__: true, 34 | stack: err.stack, 35 | message: 'Invalid argument for event.reply(), first argument must be null or Error', 36 | code: 'EINVALIDARGS', 37 | }); 38 | 39 | return false; 40 | }; 41 | 42 | common._unwrapError = function (args) { 43 | let err = args[0]; 44 | 45 | if ( err && err.__error__ ) { 46 | return err; 47 | } 48 | 49 | return null; 50 | }; 51 | 52 | common._popOptions = function (args) { 53 | let opts = args[args.length - 1]; 54 | 55 | if ( opts && typeof opts === 'object' && opts.__ipc__ ) { 56 | args.pop(); // args.splice(-1,1); 57 | return opts; 58 | } 59 | 60 | return null; 61 | }; 62 | 63 | common._popReplyAndTimeout = function (args) { 64 | // arguments check 65 | let reply, timeout; 66 | let lastArg = args[args.length - 1]; 67 | 68 | if (typeof lastArg === 'number') { 69 | if ( args.length < 2 ) { 70 | return null; 71 | } 72 | 73 | timeout = lastArg; 74 | lastArg = args[args.length - 2]; 75 | if (typeof lastArg !== 'function') { 76 | return null; 77 | } 78 | 79 | reply = lastArg; 80 | args.splice(-2,2); 81 | } else { 82 | if (typeof lastArg !== 'function') { 83 | return null; 84 | } 85 | 86 | reply = lastArg; 87 | timeout = 5000; 88 | args.pop(); 89 | } 90 | 91 | return { 92 | reply: reply, 93 | timeout: timeout, 94 | }; 95 | }; 96 | 97 | /** 98 | * @method option 99 | * @param {object} - opts 100 | * @param {boolean} - opts.excludeSelf 101 | * @param {boolean} - opts.waitForReply 102 | * @param {number} - opts.timeout 103 | * 104 | * Ipc option used as last arguments in message. 105 | */ 106 | common.option = function (opts) { 107 | opts.__ipc__ = true; 108 | return opts; 109 | }; 110 | 111 | /** 112 | * @class ErrorTimeout 113 | */ 114 | class ErrorTimeout extends Error { 115 | /** 116 | * @param {string} message 117 | * @param {string} sessionId 118 | * @param {number} timeout 119 | */ 120 | constructor ( message, sessionId, timeout ) { 121 | super(`ipc timeout. message: ${message}, session: ${sessionId}`); 122 | 123 | this.code = 'ETIMEDOUT'; 124 | this.ipc = message; 125 | this.sessionId = sessionId; 126 | this.timeout = timeout; 127 | } 128 | } 129 | 130 | /** 131 | * @class ErrorWinClosed 132 | */ 133 | class ErrorWinClosed extends Error { 134 | /** 135 | * @param {string} message 136 | * @param {string} winID 137 | */ 138 | constructor ( message, winID ) { 139 | super(`ipc failed to reply, window ${winID} closed, message: ${message}`); 140 | 141 | this.code = 'EWINCLOSED'; 142 | this.ipc = message; 143 | this.winID = winID; 144 | } 145 | } 146 | 147 | common.ErrorTimeout = ErrorTimeout; 148 | common.ErrorWinClosed = ErrorWinClosed; 149 | 150 | module.exports = common; 151 | -------------------------------------------------------------------------------- /lib/ipc-main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if ( global.__electron_ipc_plus__ ) { 4 | console.warn(`A different version of electron-ipc-plus already running in the process: ${global.__electron_ipc_plus__.id}, make sure your dependencies use the same version of electron-ipc-plus.`); 5 | } 6 | 7 | /** 8 | * @module ipcPlus 9 | */ 10 | let ipcPlus = {}; 11 | module.exports = ipcPlus; 12 | 13 | global.__electron_ipc_plus__ = ipcPlus; 14 | 15 | // requires 16 | const {app, ipcMain, BrowserWindow} = require('electron'); 17 | const common = require('./common'); 18 | 19 | const pkgJson = require('../package.json'); 20 | const moduleID = `${pkgJson.name}@${pkgJson.version}`; 21 | 22 | let _nextSessionId = 1000; 23 | let _id2sessionInfo = {}; 24 | let _debug = false; 25 | 26 | let _ErrorTimeout = common.ErrorTimeout; 27 | let _ErrorWinClosed = common.ErrorWinClosed; 28 | let _wrapError = common._wrapError; 29 | let _unwrapError = common._unwrapError; 30 | let _popOptions = common._popOptions; 31 | let _popReplyAndTimeout = common._popReplyAndTimeout; 32 | let _ipcOption = common.option; 33 | 34 | // ======================================== 35 | // exports 36 | // ======================================== 37 | 38 | /** 39 | * @property id 40 | */ 41 | ipcPlus.id = moduleID; 42 | 43 | // internal uses 44 | ipcPlus.internal = { 45 | _popReplyAndTimeout, 46 | _popOptions, 47 | _wrapError, 48 | _unwrapError, 49 | _newSession, 50 | _closeSession, 51 | }; 52 | 53 | /** 54 | * @method option 55 | * @param {object} opts 56 | * @param {boolean} opts.excludeSelf 57 | * @param {number} [opts.sessionId] - used internally 58 | * @param {boolean} [opts.waitForReply] - used internally 59 | * @param {number} [opts.timeout] - used internally 60 | * 61 | * Ipc option used as last arguments in message. 62 | */ 63 | ipcPlus.option = _ipcOption; 64 | 65 | /** 66 | * @method on 67 | * 68 | * Same as ipcMain.on 69 | */ 70 | ipcPlus.on = ipcMain.on.bind(ipcMain); 71 | 72 | /** 73 | * @method once 74 | * 75 | * Same as ipcMain.once 76 | */ 77 | ipcPlus.once = ipcMain.once.bind(ipcMain); 78 | 79 | /** 80 | * @method removeListener 81 | * 82 | * Same as `ipcMain.removeListener`. 83 | */ 84 | ipcPlus.removeListener = ipcMain.removeListener.bind(ipcMain); 85 | 86 | /** 87 | * @method sendToAll 88 | * @param {string} message 89 | * @param {...*} [args] - whatever arguments the message needs 90 | * @param {object} [options] - you can indicate the options by ipcPlus.option({ excludeSelf: true }) 91 | * 92 | * Send `message` with `...args` to all opened window and to main process asynchronously. 93 | */ 94 | ipcPlus.sendToAll = function (message, ...args) { 95 | if (args.length) { 96 | let excludeSelf = false; 97 | let opts = _popOptions(args); 98 | 99 | // check options 100 | if (opts && opts.excludeSelf) { 101 | excludeSelf = true; 102 | } 103 | 104 | args = [message, ...args]; 105 | 106 | // send 107 | if (!excludeSelf) { 108 | _main2main.apply(null, args); 109 | } 110 | _send2wins.apply(null, args); 111 | 112 | return; 113 | } 114 | 115 | _main2main(message); 116 | _send2wins(message); 117 | }; 118 | 119 | /** 120 | * @method sendToWins 121 | * @param {string} message 122 | * @param {...*} [args] - whatever arguments the message needs 123 | * 124 | * Send `message` with `...args` to all opened windows asynchronously. The renderer process 125 | * can handle it by listening to the message through the `electron.ipcRenderer` or `ipcPlus` module. 126 | * 127 | * @example 128 | * **Send IPC message (main process)** 129 | * 130 | * ```js 131 | * const ipcPlus = require('electron-ipc-plus'); 132 | * 133 | * ipcPlus.sendToWins('foo:bar', 'Hello World!'); 134 | * ``` 135 | * 136 | * **Receive IPC message (renderer process)** 137 | * 138 | * ```html 139 | * 140 | * 141 | * 148 | * 149 | * 150 | * ``` 151 | */ 152 | ipcPlus.sendToWins = _send2wins; 153 | 154 | /** 155 | * @method sendToMain 156 | * @param {string} message 157 | * @param {...*} [args] - whatever arguments the message needs 158 | * @param {function} [callback] - You can specify a callback function to receive IPC reply at the last or the 2nd last argument. 159 | * @param {number} [timeout] - You can specify a timeout for the callback at the last argument. If no timeout specified, it will be 5000ms. 160 | * @return {number} sessionID 161 | * 162 | * Send `message` with `...args` to main process asynchronously. It is possible to add a callback as the last or the 2nd last argument 163 | * to receive replies from the IPC receiver. 164 | * 165 | * Example: 166 | * 167 | * **Send IPC message (main process)** 168 | * 169 | * ```js 170 | * const ipcPlus = require('electron-ipc-plus'); 171 | * 172 | * ipcPlus.sendToMain('foobar:say-hello', (err, msg) => { 173 | * if ( err.code === 'ETIMEDOUT' ) { 174 | * console.error('Timeout for ipc message foobar:say-hello'); 175 | * return; 176 | * } 177 | * 178 | * console.log(`foobar replied: ${msg}`); 179 | * }); 180 | * ``` 181 | * 182 | * **Receive and Reply IPC message (main process)** 183 | * 184 | * ```js 185 | * const {ipcMain} = require('electron'); 186 | * 187 | * ipcMain.on('foobar:say-hello', event => { 188 | * event.reply(null, 'Hi'); 189 | * }); 190 | * ``` 191 | */ 192 | ipcPlus.sendToMain = function (message, ...args) { 193 | if ( typeof message !== 'string' ) { 194 | console.error('Call to `sendToMain` failed. The message must be a string.'); 195 | return; 196 | } 197 | 198 | let opts = _popReplyAndTimeout(args); 199 | if ( !opts ) { 200 | args = [message, ...args]; 201 | if ( _main2main.apply ( null, args ) === false ) { 202 | console.error( `sendToMain "${message}" failed, no response received.` ); 203 | } 204 | return; 205 | } 206 | 207 | let sessionId = _newSession(message, 'main', opts.reply, opts.timeout); 208 | 209 | args = [message, ...args, _ipcOption({ 210 | sessionId: sessionId, 211 | waitForReply: true, 212 | timeout: opts.timeout, // this is only used as debug info 213 | })]; 214 | 215 | if ( _main2mainOpts.apply ( null, args ) === false ) { 216 | console.error( `sendToMain "${message}" failed, no response received.` ); 217 | } 218 | 219 | return sessionId; 220 | }; 221 | 222 | /** 223 | * @method sendToWin 224 | * @param {BrowserWindow} win 225 | * @param {string} message 226 | * @param {...*} [args] - whatever arguments the message needs 227 | * @param {object} [options] - you can indicate the options by ipcPlus.option({ excludeSelf: true }) 228 | * 229 | * Send `message` with `...args` to specific window. 230 | */ 231 | ipcPlus.sendToWin = function (win, message, ...args) { 232 | // NOTE: it is possible the webContents is destroyed 233 | if ( win.webContents.isDestroyed() ) { 234 | return; 235 | } 236 | 237 | // TODO: what is win.webContents.isLoading()? 238 | // should we setInterval to recheck/retry for several times? 239 | 240 | if ( typeof message !== 'string' ) { 241 | console.error(`Send message failed for "${message}". The message must be a string`); 242 | return; 243 | } 244 | 245 | let opts = _popReplyAndTimeout(args); 246 | if ( !opts ) { 247 | args = [win, message, ...args]; 248 | if ( _send2win.apply(null, args) === false ) { 249 | console.error( `send message "${message}" to window failed. No response was received.` ); 250 | } 251 | return; 252 | } 253 | 254 | let sessionId = _newSession(message, `${win.id}@main`, opts.reply, opts.timeout, win); 255 | 256 | // 257 | args = [win, `${moduleID}:main2renderer`, message, ...args, _ipcOption({ 258 | sessionId: sessionId, 259 | waitForReply: true, 260 | timeout: opts.timeout, // this is only used as debug info 261 | })]; 262 | _send2win.apply(null, args); 263 | 264 | return sessionId; 265 | }; 266 | 267 | /** 268 | * @method cancelRequest 269 | * @param {number} sessionId 270 | * 271 | * Cancel request sent to main or renderer process. 272 | */ 273 | ipcPlus.cancelRequest = function (sessionId) { 274 | _closeSession(sessionId); 275 | }; 276 | 277 | /** 278 | * @method _closeAllSessions 279 | * 280 | * Force close all sessions. 281 | * Usually you don't need to call this function. This is for page reload or app relaunch purpose. 282 | */ 283 | ipcPlus._closeAllSessions = function () { 284 | let ids = Object.keys(_id2sessionInfo); 285 | 286 | for ( let i = 0; i < ids.length; ++i ) { 287 | let sessionId = ids[i]; 288 | _closeSession (sessionId); 289 | } 290 | }; 291 | 292 | /** 293 | * @property {boolean} debug 294 | * 295 | * Turn on/off the debug code in the module. 296 | */ 297 | Object.defineProperty(ipcPlus, 'debug', { 298 | enumerable: true, 299 | get () { return _debug; }, 300 | set ( value ) { _debug = value; }, 301 | }); 302 | 303 | // ======================================== 304 | // Internal 305 | // ======================================== 306 | 307 | /** 308 | * @param {string} message 309 | * @param {string} prefix - can be 'main', '${winID}@renderer' and so on... 310 | * @param {function} fn - callback function 311 | * @param {number} timeout 312 | * @param {BrowserWindow} [win] 313 | */ 314 | function _newSession ( message, prefix, fn, timeout, win ) { 315 | let sessionId = `${prefix}:${_nextSessionId++}`; 316 | let timeoutId; 317 | 318 | if ( timeout !== -1 ) { 319 | timeoutId = setTimeout(() => { 320 | let info = _id2sessionInfo[sessionId]; 321 | 322 | if ( info ) { 323 | delete _id2sessionInfo[sessionId]; 324 | 325 | info.callback(new _ErrorTimeout( message, sessionId, timeout )); 326 | } 327 | 328 | // DISABLE 329 | // if ( _debug ) { 330 | // console.warn(`ipc timeout. message: ${message}, session: ${sessionId}`); 331 | // } 332 | }, timeout); 333 | } 334 | 335 | _id2sessionInfo[sessionId] = { 336 | sessionId: sessionId, 337 | timeoutId: timeoutId, 338 | callback: fn, 339 | win: win, 340 | message: message, 341 | }; 342 | 343 | return sessionId; 344 | } 345 | 346 | function _closeSession ( sessionId ) { 347 | let info = _id2sessionInfo[sessionId]; 348 | 349 | if ( info ) { 350 | delete _id2sessionInfo[sessionId]; 351 | 352 | if ( info.timeoutId ) { 353 | clearTimeout(info.timeoutId); 354 | } 355 | } 356 | 357 | return info; 358 | } 359 | 360 | function _closeAllSessionsInWin (win) { 361 | let ids = Object.keys(_id2sessionInfo); 362 | 363 | for ( let i = 0; i < ids.length; ++i ) { 364 | let sessionId = ids[i]; 365 | let info = _id2sessionInfo[sessionId]; 366 | 367 | if ( info && info.win && info.win === win ) { 368 | delete _id2sessionInfo[sessionId]; 369 | 370 | if ( info.timeoutId ) { 371 | clearTimeout(info.timeoutId); 372 | } 373 | 374 | info.callback(new _ErrorWinClosed(info.message, win)); 375 | } 376 | } 377 | } 378 | 379 | function _send2win (win, ...args) { 380 | // NOTE: it is possible the webContents is destroyed 381 | if ( win.webContents.isDestroyed() ) { 382 | return false; 383 | } 384 | 385 | // TODO: what if win.webContents.isLoading()? 386 | // should we setInterval to recheck/retry for several times? 387 | 388 | win.webContents.send.apply(win.webContents, args); 389 | 390 | return true; 391 | } 392 | 393 | function _send2wins (message, ...args) { 394 | args = [message, ...args]; 395 | 396 | let winlist = BrowserWindow.getAllWindows(); 397 | 398 | for ( let i = 0; i < winlist.length; ++i ) { 399 | let win = winlist[i]; 400 | 401 | // NOTE: it is possible the webContents is destroyed 402 | if ( win.webContents.isDestroyed() ) { 403 | continue; 404 | } 405 | 406 | // TODO: what if win.webContents.isLoading()? 407 | // should we setInterval to recheck/retry for several times? 408 | 409 | win.webContents.send.apply(win.webContents, args); 410 | } 411 | } 412 | 413 | /** 414 | * Send `args...` to windows except the excluded 415 | * @method _main2renderersExclude 416 | * @param {object} excluded - A [WebContents](https://github.com/atom/electron/blob/master/docs/api/browser-window.md#class-webcontents) object. 417 | * @param {...*} [args] - whatever arguments the message needs 418 | */ 419 | function _main2renderersExclude (excluded, ...args) { 420 | let winlist = BrowserWindow.getAllWindows(); 421 | 422 | for ( let i = 0; i < winlist.length; ++i ) { 423 | let win = winlist[i]; 424 | 425 | // NOTE: it is possible the webContents is destroyed 426 | if ( win.webContents.isDestroyed() ) { 427 | continue; 428 | } 429 | 430 | // if window excluded 431 | if ( win.webContents === excluded ) { 432 | continue; 433 | } 434 | 435 | // TODO: what if win.webContents.isLoading()? 436 | // should we setInterval to recheck/retry for several times? 437 | 438 | win.webContents.send.apply(win.webContents, args); 439 | } 440 | } 441 | 442 | function _main2renderers (message, ...args) { 443 | if ( args.length === 0 ) { 444 | _send2wins( message ); 445 | return; 446 | } 447 | 448 | // send 449 | _send2wins.apply( null, [message, ...args] ); 450 | } 451 | 452 | function _main2mainOpts (message, ...args) { 453 | let event = { 454 | senderType: 'main', 455 | sender: { 456 | send: ipcPlus.sendToMain 457 | } 458 | }; 459 | 460 | if ( args.length === 0 ) { 461 | return ipcMain.emit( message, event ); 462 | } 463 | 464 | // process waitForReply option 465 | let opts = _popOptions(args); 466 | if ( opts && opts.waitForReply ) { 467 | // NOTE: do not directly use message in event.reply, it will cause Electron devtools crash 468 | let msg = message; 469 | event.reply = function (...replyArgs) { 470 | if ( _wrapError(replyArgs) === false ) { 471 | console.warn(`Invalid argument for event.reply of "${msg}": the first argument must be an instance of "Error" or "null"`); 472 | } 473 | 474 | let replyOpts = _ipcOption({ 475 | sessionId: opts.sessionId 476 | }); 477 | replyArgs = [`${moduleID}:reply`, event, ...replyArgs, replyOpts]; 478 | return ipcMain.emit.apply( ipcMain, replyArgs ); 479 | }; 480 | } 481 | 482 | // insert event as 2nd parameter in args 483 | args = [message, event, ...args]; 484 | return ipcMain.emit.apply( ipcMain, args ); 485 | } 486 | 487 | function _main2main (message, ...args) { 488 | let event = { 489 | senderType: 'main', 490 | sender: { 491 | send: ipcPlus.sendToMain 492 | } 493 | }; 494 | 495 | if ( args.length === 0 ) { 496 | return ipcMain.emit( message, event ); 497 | } 498 | 499 | // insert event as 2nd parameter in args 500 | args = [message, event, ...args]; 501 | return ipcMain.emit.apply( ipcMain, args ); 502 | } 503 | 504 | function _renderer2mainOpts (event, message, ...args) { 505 | if ( args.length === 0 ) { 506 | return ipcMain.emit( message, event ); 507 | } 508 | 509 | // process waitForReply option 510 | let opts = _popOptions(args); 511 | if ( opts && opts.waitForReply ) { 512 | // NOTE: do not directly use `event` and `message` in event.reply, it will cause Electron devtools crash 513 | let sender = event.sender; 514 | let msg = message; 515 | 516 | event.reply = function (...replyArgs) { 517 | // if the sender is invalid (destroyed) 518 | if ( sender.isDestroyed() ) { 519 | return; 520 | } 521 | 522 | if ( _wrapError(replyArgs) === false ) { 523 | console.warn(`Invalid argument for event.reply of "${msg}": the first argument must be an instance of "Error" or "null"`); 524 | } 525 | 526 | let replyOpts = _ipcOption({ 527 | sessionId: opts.sessionId 528 | }); 529 | replyArgs = [`${moduleID}:reply`, ...replyArgs, replyOpts]; 530 | return sender.send.apply( sender, replyArgs ); 531 | }; 532 | } 533 | 534 | // refine the args 535 | args = [message, event, ...args]; 536 | return ipcMain.emit.apply( ipcMain, args ); 537 | } 538 | 539 | function _renderer2main (event, message, ...args) { 540 | if ( args.length === 0 ) { 541 | return ipcMain.emit( message, event ); 542 | } 543 | 544 | // refine the args 545 | args = [message, event, ...args]; 546 | return ipcMain.emit.apply( ipcMain, args ); 547 | } 548 | 549 | function _renderer2renderersOpts (event, message, ...args) { 550 | // check options 551 | let opts = _popOptions(args); 552 | if (opts && opts.excludeSelf) { 553 | _main2renderersExclude.apply( null, [event.sender, message, ...args] ); 554 | return; 555 | } 556 | 557 | _main2renderers.apply(null, [message, ...args]); 558 | } 559 | 560 | // ======================================== 561 | // app event 562 | // ======================================== 563 | 564 | app.on('browser-window-created', (event, browserWin) => { 565 | // close all session once the window closed 566 | browserWin.once('closed', () => { 567 | _closeAllSessionsInWin(browserWin); 568 | }); 569 | }); 570 | 571 | // ======================================== 572 | // ipcPlus 573 | // ======================================== 574 | 575 | ipcMain.on(`${moduleID}:renderer2all`, (event, message, ...args) => { 576 | let opts = _popOptions(args); 577 | 578 | _renderer2main.apply(null, [event, message, ...args]); 579 | 580 | if (opts && opts.excludeSelf) { 581 | _main2renderersExclude.apply( null, [event.sender, message, ...args] ); 582 | } else { 583 | _main2renderers.apply(null, [message, ...args]); 584 | } 585 | }); 586 | 587 | ipcMain.on(`${moduleID}:renderer2wins`, _renderer2renderersOpts ); 588 | 589 | ipcMain.on(`${moduleID}:renderer2main`, (event, message, ...args) => { 590 | if ( _renderer2mainOpts.apply ( null, [event, message, ...args] ) === false ) { 591 | console.error( `Message "${message}" from renderer to main failed, no response receieved.` ); 592 | } 593 | }); 594 | 595 | ipcMain.on(`${moduleID}:reply`, (event, ...args) => { 596 | let opts = _popOptions(args); 597 | 598 | // create a new Error in current process 599 | // NOTE: don't do this in _unwrapError, it will make the new Error have wrong stack. 600 | let err = _unwrapError(args); 601 | if ( err ) { 602 | let lines = err.stack.split('\n'); 603 | lines.shift(); // remove the message cause we add it in new Error; 604 | 605 | let newErr = new Error(err.message); 606 | newErr.stack += '\n\t--------------------\n' + lines.join('\n'); 607 | newErr.code = err.code; 608 | newErr.code = err.code; 609 | newErr.errno = err.errno; 610 | newErr.syscall = err.syscall; 611 | 612 | args[0] = newErr; 613 | } 614 | 615 | // NOTE: we must close session before it apply, this will prevent window.close() invoked in 616 | // reply callback will make _closeSession called second times. 617 | let info = _closeSession(opts.sessionId); 618 | if (info) { 619 | info.callback.apply(null, args); 620 | } 621 | }); 622 | -------------------------------------------------------------------------------- /lib/ipc-renderer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if ( window.__electron_ipc_plus__ ) { 4 | console.warn(`A different version of electron-ipc-plus already running in the process: ${window.__electron_ipc_plus__.id}, make sure your dependencies use the same version of electron-ipc-plus.`); 5 | } 6 | 7 | /** 8 | * @module ipcPlus 9 | */ 10 | let ipcPlus = {}; 11 | module.exports = ipcPlus; 12 | 13 | window.__electron_ipc_plus__ = ipcPlus; 14 | 15 | const pkgJson = require('../package.json'); 16 | const moduleID = `${pkgJson.name}@${pkgJson.version}`; 17 | 18 | // requires 19 | const {remote, ipcRenderer} = require('electron'); 20 | const common = require('./common'); 21 | 22 | // get window id 23 | const winID = remote.getCurrentWindow().id; 24 | 25 | let _nextSessionId = 1000; 26 | let _id2sessionInfo = {}; 27 | let _debug = false; 28 | 29 | let _ErrorTimeout = common.ErrorTimeout; 30 | let _wrapError = common._wrapError; 31 | let _unwrapError = common._unwrapError; 32 | let _popOptions = common._popOptions; 33 | let _popReplyAndTimeout = common._popReplyAndTimeout; 34 | let _ipcOption = common.option; 35 | 36 | // ========================== 37 | // exports 38 | // ========================== 39 | 40 | /** 41 | * @property id 42 | */ 43 | ipcPlus.id = moduleID; 44 | 45 | // internal uses 46 | ipcPlus.internal = { 47 | _popReplyAndTimeout, 48 | _popOptions, 49 | _wrapError, 50 | _unwrapError, 51 | _newSession, 52 | _closeSession, 53 | }; 54 | 55 | /** 56 | * @method option 57 | * @param {object} opts 58 | * @param {boolean} opts.excludeSelf - exclude send ipc message to main process when calling `ipcPlusM.sendToAll`. 59 | * @param {number} [opts.sessionId] - used internally. 60 | * @param {boolean} [opts.waitForReply] - used internally. 61 | * @param {number} [opts.timeout] - used internally. 62 | * 63 | * Ipc option used in `ipcPlusM.sendToAll` and `ipcPlusM.sendToWins`. 64 | */ 65 | ipcPlus.option = _ipcOption; 66 | 67 | /** 68 | * @method on 69 | * 70 | * Same as `ipcRenderer.on`. 71 | */ 72 | ipcPlus.on = ipcRenderer.on.bind(ipcRenderer); 73 | 74 | /** 75 | * @method once 76 | * 77 | * Same as `ipcRenderer.once`. 78 | */ 79 | ipcPlus.once = ipcRenderer.once.bind(ipcRenderer); 80 | 81 | /** 82 | * @method removeListener 83 | * 84 | * Same as `ipcRenderer.removeListener`. 85 | */ 86 | ipcPlus.removeListener = ipcRenderer.removeListener.bind(ipcRenderer); 87 | 88 | /** 89 | * @method sendToAll 90 | * @param {string} message - Ipc message. 91 | * @param {...} [args] - Whatever arguments the message needs. 92 | * @param {object} [options] - You can indicate the last argument as an IPC option by `ipcPlus.option({...})`. 93 | * 94 | * Send `message` with `...args` to all opened window and to main process asynchronously. 95 | * 96 | */ 97 | ipcPlus.sendToAll = function (message, ...args) { 98 | if ( typeof message !== 'string' ) { 99 | console.error('Call to `sendToAll` failed. The message must be a string.'); 100 | return; 101 | } 102 | 103 | ipcRenderer.send.apply( ipcRenderer, [`${moduleID}:renderer2all`, message, ...args] ); 104 | }; 105 | 106 | /** 107 | * @method sendToWins 108 | * @param {string} message 109 | * @param {...*} [args] - whatever arguments the message needs 110 | * @param {object} [options] - You can indicate the last argument as an IPC option by `ipcPlus.option({...})`. 111 | * 112 | * Send `message` with `...args` to all opened windows asynchronously. The renderer process 113 | * can handle it by listening to the message through the `ipcRenderer` module. 114 | */ 115 | ipcPlus.sendToWins = function (message, ...args) { 116 | if ( typeof message !== 'string' ) { 117 | console.error('Call to `sendToWins` failed. The message must be a string.'); 118 | return; 119 | } 120 | 121 | ipcRenderer.send.apply( ipcRenderer, [`${moduleID}:renderer2wins`, message, ...args] ); 122 | }; 123 | 124 | /** 125 | * @method sendToMainSync 126 | * @param {string} message 127 | * @param {...*} [args] - whatever arguments the message needs 128 | * @return {Object} results 129 | * 130 | * Send `message` with `...args` to main process synchronized and return a result which is responded from main process 131 | */ 132 | ipcPlus.sendToMainSync = function (message, ...args) { 133 | if ( typeof message !== 'string' ) { 134 | console.error('Call to `sendToMainSync` failed. The message must be a string.'); 135 | return; 136 | } 137 | 138 | return ipcRenderer.sendSync.apply( ipcRenderer, [message, ...args] ); 139 | }; 140 | 141 | /** 142 | * @method sendToMain 143 | * @param {string} message 144 | * @param {...*} [args] - whatever arguments the message needs 145 | * 146 | * Send `message` with `...args` to main process asynchronously. 147 | */ 148 | ipcPlus.sendToMain = function (message, ...args) { 149 | if ( typeof message !== 'string' ) { 150 | console.error('Call to `sendToMain` failed. The message must be a string.'); 151 | return; 152 | } 153 | 154 | let opts = _popReplyAndTimeout(args); 155 | let sessionId; 156 | 157 | if ( opts ) { 158 | sessionId = _newSession(message, `${winID}@renderer`, opts.reply, opts.timeout); 159 | 160 | args = [`${moduleID}:renderer2main`, message, ...args, _ipcOption({ 161 | sessionId: sessionId, 162 | waitForReply: true, 163 | timeout: opts.timeout, // this is only used as debug info 164 | })]; 165 | } else { 166 | args = [message, ...args]; 167 | } 168 | 169 | ipcRenderer.send.apply( ipcRenderer, args ); 170 | 171 | return sessionId; 172 | }; 173 | 174 | /** 175 | * @method cancelRequest 176 | * @param {number} sessionId 177 | * 178 | * Cancel request sent to main or renderer process. 179 | */ 180 | ipcPlus.cancelRequest = function (sessionId) { 181 | _closeSession(sessionId); 182 | }; 183 | 184 | /** 185 | * @method _closeAllSessions 186 | * 187 | * Force close all sessions. 188 | * Usually you don't need to call this function. This is for page reload or app relaunch purpose. 189 | */ 190 | ipcPlus._closeAllSessions = function () { 191 | let ids = Object.keys(_id2sessionInfo); 192 | 193 | for ( let i = 0; i < ids.length; ++i ) { 194 | let sessionId = ids[i]; 195 | _closeSession (sessionId); 196 | } 197 | }; 198 | 199 | /** 200 | * @property {boolean} debug 201 | * 202 | * Turn on/off the debug code in the module. 203 | */ 204 | Object.defineProperty(ipcPlus, 'debug', { 205 | enumerable: true, 206 | get () { return _debug; }, 207 | set ( value ) { _debug = value; }, 208 | }); 209 | 210 | // ======================================== 211 | // Internal 212 | // ======================================== 213 | 214 | function _newSession ( message, prefix, fn, timeout ) { 215 | let sessionId = `${prefix}:${_nextSessionId++}`; 216 | let timeoutId; 217 | 218 | if ( timeout !== -1 ) { 219 | timeoutId = setTimeout(() => { 220 | let info = _id2sessionInfo[sessionId]; 221 | 222 | if ( info ) { 223 | delete _id2sessionInfo[sessionId]; 224 | 225 | info.callback(new _ErrorTimeout( message, sessionId, timeout )); 226 | } 227 | 228 | // DISABLE 229 | // if ( _debug ) { 230 | // console.warn(`ipc timeout. message: ${message}, session: ${sessionId}`); 231 | // } 232 | }, timeout); 233 | } 234 | 235 | _id2sessionInfo[sessionId] = { 236 | sessionId: sessionId, 237 | timeoutId: timeoutId, 238 | callback: fn, 239 | message: message, 240 | }; 241 | 242 | return sessionId; 243 | } 244 | 245 | function _closeSession ( sessionId ) { 246 | let info = _id2sessionInfo[sessionId]; 247 | 248 | if ( info ) { 249 | delete _id2sessionInfo[sessionId]; 250 | 251 | if ( info.timeoutId ) { 252 | clearTimeout(info.timeoutId); 253 | } 254 | } 255 | 256 | return info; 257 | } 258 | 259 | function _main2rendererOpts (event, message, ...args) { 260 | if ( args.length === 0 ) { 261 | return ipcRenderer.emit( message, event ); 262 | } 263 | 264 | // process waitForReply option 265 | let opts = _popOptions(args); 266 | if ( opts && opts.waitForReply ) { 267 | // NOTE: do not directly use event.sender in event.reply, it will cause Electron devtools crash 268 | let sender = event.sender; 269 | let msg = message; 270 | event.reply = function (...replyArgs) { 271 | if ( _wrapError(replyArgs) === false ) { 272 | console.warn(`Invalid argument for event.reply of "${msg}": the first argument must be an instance of Error or null`); 273 | } 274 | 275 | let replyOpts = _ipcOption({ 276 | sessionId: opts.sessionId 277 | }); 278 | replyArgs = [`${moduleID}:reply`, ...replyArgs, replyOpts]; 279 | return sender.send.apply( sender, replyArgs ); 280 | }; 281 | } 282 | 283 | // refine the args 284 | args = [message, event, ...args]; 285 | return ipcRenderer.emit.apply( ipcRenderer, args ); 286 | } 287 | 288 | // ======================================== 289 | // ipcPlus 290 | // ======================================== 291 | 292 | ipcRenderer.on(`${moduleID}:main2renderer`, (event, message, ...args) => { 293 | if ( _main2rendererOpts.apply ( null, [event, message, ...args] ) === false ) { 294 | console.error( `Message "${message}" from main to renderer failed, no response was received.` ); 295 | } 296 | }); 297 | 298 | ipcRenderer.on(`${moduleID}:reply`, (event, ...args) => { 299 | let opts = _popOptions(args); 300 | 301 | // create a new Error in current process 302 | // NOTE: don't do this in _unwrapError, it will make the new Error have wrong stack. 303 | let err = _unwrapError(args); 304 | if ( err ) { 305 | let lines = err.stack.split('\n'); 306 | lines.shift(); // remove the message cause we add it in new Error; 307 | 308 | let newErr = new Error(err.message); 309 | newErr.stack += '\n\t--------------------\n' + lines.join('\n'); 310 | newErr.code = err.code; 311 | newErr.code = err.code; 312 | newErr.errno = err.errno; 313 | newErr.syscall = err.syscall; 314 | 315 | args[0] = newErr; 316 | } 317 | 318 | // NOTE: we must close session before it apply, this will prevent window.close() invoked in 319 | // reply callback will make _closeSession called second times. 320 | let info = _closeSession(opts.sessionId); 321 | if (info) { 322 | info.callback.apply(null, args); 323 | } 324 | }); 325 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-ipc-plus", 3 | "version": "1.3.4", 4 | "description": "Improved IPC operations for electron", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "electron", 8 | "test": "mocha test/*.spec.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/jwu/electron-ipc-plus.git" 13 | }, 14 | "keywords": [ 15 | "Electron", 16 | "ipc" 17 | ], 18 | "author": "jwu", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/jwu/electron-ipc-plus/issues" 22 | }, 23 | "homepage": "https://github.com/jwu/electron-ipc-plus", 24 | "dependencies": { 25 | "electron-platform": "^1.2.0" 26 | }, 27 | "devDependencies": { 28 | "electron": "^1.6.2", 29 | "mocha": "^3.2.0", 30 | "spectron": "^3.6.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/fixtures/app-main2all-exclude-self/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/app-main2all-exclude-self/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | ipcPlus.sendToAll('app:hello', ipcPlus.option({excludeSelf: true})); 15 | ipcPlus.sendToAll('app:hello', 'alpha', ipcPlus.option({excludeSelf: true})); 16 | ipcPlus.sendToAll('app:hello', 'beta', ipcPlus.option({excludeSelf: true})); 17 | ipcPlus.sendToAll('app:hello', 'cell', ipcPlus.option({excludeSelf: true})); 18 | } 19 | } 20 | 21 | app.on('ready', function () { 22 | for ( let i = 0; i < maxWins; ++i ) { 23 | let win = new BrowserWindow({ 24 | x: 100 + 210*i, 25 | y: 100, 26 | width: 200, 27 | height: 200 28 | }); 29 | win.loadURL('file://' + __dirname + '/index.html'); 30 | win.webContents.once('dom-ready', domReady); 31 | 32 | wins.push(win); 33 | } 34 | }); 35 | 36 | ipcPlus.on('app:hello', (event, ...args) => { 37 | global.ipcCalls.push(`app:hello ${args}`); 38 | }); 39 | -------------------------------------------------------------------------------- /test/fixtures/app-main2all-exclude-self/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2all/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/app-main2all/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | ipcPlus.sendToAll('app:hello'); 15 | ipcPlus.sendToAll('app:hello', 'alpha'); 16 | ipcPlus.sendToAll('app:hello', 'beta'); 17 | ipcPlus.sendToAll('app:hello', 'cell'); 18 | } 19 | } 20 | 21 | app.on('ready', function () { 22 | for ( let i = 0; i < maxWins; ++i ) { 23 | let win = new BrowserWindow({ 24 | x: 100 + 210*i, 25 | y: 100, 26 | width: 200, 27 | height: 200 28 | }); 29 | win.loadURL('file://' + __dirname + '/index.html'); 30 | win.webContents.once('dom-ready', domReady); 31 | 32 | wins.push(win); 33 | } 34 | }); 35 | 36 | ipcPlus.on('app:hello', (event, ...args) => { 37 | global.ipcCalls.push(`app:hello ${args}`); 38 | }); 39 | -------------------------------------------------------------------------------- /test/fixtures/app-main2all/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2main-reply/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/fixtures/app-main2main-reply/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | 15 | ipcPlus.on('app:hello', (event, ...args) => { 16 | global.ipcCalls.push(`app:hello ${args}`); 17 | event.reply(`${args} received`); 18 | }); 19 | ipcPlus.on('app:hello-error', (event, ...args) => { 20 | global.ipcCalls.push(`app:hello ${args}`); 21 | event.reply(new Error('user'), `${args} failed`); 22 | }); 23 | 24 | ipcPlus.sendToMain('app:hello', (err, msg) => { 25 | global.ipcCalls.push(`${msg}`); 26 | }); 27 | ipcPlus.sendToMain('app:hello', 'alpha', (err, msg) => { 28 | global.ipcCalls.push(`${msg}`); 29 | }); 30 | ipcPlus.sendToMain('app:hello', 'beta', (err, msg) => { 31 | global.ipcCalls.push(`${msg}`); 32 | }); 33 | ipcPlus.sendToMain('app:hello', 'cell', (err, msg) => { 34 | global.ipcCalls.push(`${msg}`); 35 | }); 36 | ipcPlus.sendToMain('app:hello-error', 'foobar', (err, msg) => { 37 | global.ipcCalls.push(`${err}, ${msg}`); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /test/fixtures/app-main2main-reply/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2main/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/fixtures/app-main2main/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | 15 | ipcPlus.on('app:hello', (event, ...args) => { 16 | global.ipcCalls.push(`app:hello ${args}`); 17 | }); 18 | 19 | ipcPlus.sendToMain('app:hello'); 20 | ipcPlus.sendToMain('app:hello', 'alpha'); 21 | ipcPlus.sendToMain('app:hello', 'beta'); 22 | ipcPlus.sendToMain('app:hello', 'cell'); 23 | }); 24 | -------------------------------------------------------------------------------- /test/fixtures/app-main2main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-a-user-error/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-a-user-error/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let win; 7 | 8 | function domReady () { 9 | ipcPlus.sendToWin(win, 'app:hello', (err, msg) => { 10 | if ( err ) { 11 | global.ipcCalls.push(`${err}, ${msg}`); 12 | return; 13 | } 14 | global.ipcCalls.push(`${msg}`); 15 | }); 16 | ipcPlus.sendToWin(win, 'app:hello', 'alpha', (err, msg) => { 17 | if ( err ) { 18 | global.ipcCalls.push(`${err}, ${msg}`); 19 | return; 20 | } 21 | global.ipcCalls.push(`${msg}`); 22 | }); 23 | ipcPlus.sendToWin(win, 'app:hello', 'beta', (err, msg) => { 24 | if ( err ) { 25 | global.ipcCalls.push(`${err}, ${msg}`); 26 | return; 27 | } 28 | global.ipcCalls.push(`${msg}`); 29 | }); 30 | ipcPlus.sendToWin(win, 'app:hello', 'cell', (err, msg) => { 31 | if ( err ) { 32 | global.ipcCalls.push(`${err}, ${msg}`); 33 | return; 34 | } 35 | global.ipcCalls.push(`${msg}`); 36 | }); 37 | } 38 | 39 | app.on('ready', function () { 40 | win = new BrowserWindow({ 41 | x: 100 + 210, 42 | y: 100, 43 | width: 200, 44 | height: 200 45 | }); 46 | win.loadURL('file://' + __dirname + '/index.html'); 47 | win.webContents.once('dom-ready', domReady); 48 | }); 49 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-a-user-error/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-cancel-request/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-cancel-request/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let win; 7 | 8 | function domReady () { 9 | let id; 10 | 11 | id = ipcPlus.sendToWin(win, 'app:hello', (err, msg) => { 12 | if ( err ) { 13 | global.ipcCalls.push(`${err}, ${msg}`); 14 | return; 15 | } 16 | global.ipcCalls.push(`${msg}`); 17 | }); 18 | ipcPlus.cancelRequest(id); 19 | 20 | id = ipcPlus.sendToWin(win, 'app:hello', 'alpha', (err, msg) => { 21 | if ( err ) { 22 | global.ipcCalls.push(`${err}, ${msg}`); 23 | return; 24 | } 25 | global.ipcCalls.push(`${msg}`); 26 | }); 27 | ipcPlus.cancelRequest(id); 28 | 29 | id = ipcPlus.sendToWin(win, 'app:hello', 'beta', (err, msg) => { 30 | if ( err ) { 31 | global.ipcCalls.push(`${err}, ${msg}`); 32 | return; 33 | } 34 | global.ipcCalls.push(`${msg}`); 35 | }); 36 | ipcPlus.cancelRequest(id); 37 | 38 | id = ipcPlus.sendToWin(win, 'app:hello', 'cell', (err, msg) => { 39 | if ( err ) { 40 | global.ipcCalls.push(`${err}, ${msg}`); 41 | return; 42 | } 43 | global.ipcCalls.push(`${msg}`); 44 | }); 45 | ipcPlus.cancelRequest(id); 46 | } 47 | 48 | app.on('ready', function () { 49 | win = new BrowserWindow({ 50 | x: 100 + 210, 51 | y: 100, 52 | width: 200, 53 | height: 200 54 | }); 55 | win.loadURL('file://' + __dirname + '/index.html'); 56 | win.webContents.once('dom-ready', domReady); 57 | }); 58 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-cancel-request/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-error-invalid-first-arg/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-error-invalid-first-arg/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let win; 7 | 8 | function domReady () { 9 | ipcPlus.sendToWin(win, 'app:hello', (err, msg) => { 10 | if ( err ) { 11 | global.ipcCalls.push(`${err.code}, ${msg}`); 12 | return; 13 | } 14 | global.ipcCalls.push(`${msg}`); 15 | }); 16 | ipcPlus.sendToWin(win, 'app:hello', 'alpha', (err, msg) => { 17 | if ( err ) { 18 | global.ipcCalls.push(`${err.code}, ${msg}`); 19 | return; 20 | } 21 | global.ipcCalls.push(`${msg}`); 22 | }); 23 | 24 | ipcPlus.sendToWin(win, 'app:hello', 'beta', (err, msg) => { 25 | if ( err ) { 26 | global.ipcCalls.push(`${err.code}, ${msg}`); 27 | return; 28 | } 29 | global.ipcCalls.push(`${msg}`); 30 | }); 31 | 32 | ipcPlus.sendToWin(win, 'app:hello', 'cell', (err, msg) => { 33 | if ( err ) { 34 | global.ipcCalls.push(`${err.code}, ${msg}`); 35 | return; 36 | } 37 | global.ipcCalls.push(`${msg}`); 38 | }); 39 | } 40 | 41 | app.on('ready', function () { 42 | win = new BrowserWindow({ 43 | x: 100 + 210, 44 | y: 100, 45 | width: 200, 46 | height: 200 47 | }); 48 | win.loadURL('file://' + __dirname + '/index.html'); 49 | win.webContents.once('dom-ready', domReady); 50 | }); 51 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-error-invalid-first-arg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-error-win-destroyed/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-error-win-destroyed/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-error-win-destroyed/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let win, win2; 7 | let readyCnt = 0; 8 | 9 | function domReady () { 10 | ++readyCnt; 11 | 12 | if ( readyCnt === 2 ) { 13 | ipcPlus.sendToWin(win, 'app:hello', 'foobar', (err, msg) => { 14 | if ( err ) { 15 | global.ipcCalls.push(`${err.code}, ${msg}`); 16 | return; 17 | } 18 | global.ipcCalls.push(`${msg}`); 19 | }); 20 | 21 | setTimeout(() => { 22 | win.close(); 23 | }, 100); 24 | } 25 | } 26 | 27 | app.on('ready', function () { 28 | win = new BrowserWindow({ 29 | x: 300, 30 | y: 100, 31 | width: 200, 32 | height: 200 33 | }); 34 | win.loadURL('file://' + __dirname + '/index.html'); 35 | win.webContents.once('dom-ready', domReady); 36 | 37 | win2 = new BrowserWindow({ 38 | x: 300 + 210, 39 | y: 100, 40 | width: 200, 41 | height: 200 42 | }); 43 | win2.loadURL('file://' + __dirname + '/index2.html'); 44 | win2.webContents.once('dom-ready', domReady); 45 | }); 46 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-error-win-destroyed/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-more-than-once/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-more-than-once/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let win; 7 | 8 | function domReady () { 9 | ipcPlus.sendToWin(win, 'app:hello', (err, msg) => { 10 | if ( err ) { 11 | global.ipcCalls.push(`${err}, ${msg}`); 12 | return; 13 | } 14 | global.ipcCalls.push(`${msg}`); 15 | }); 16 | 17 | ipcPlus.sendToWin(win, 'app:hello', 'alpha', (err, msg) => { 18 | if ( err ) { 19 | global.ipcCalls.push(`${err}, ${msg}`); 20 | return; 21 | } 22 | global.ipcCalls.push(`${msg}`); 23 | }); 24 | 25 | ipcPlus.sendToWin(win, 'app:hello', 'beta', (err, msg) => { 26 | if ( err ) { 27 | global.ipcCalls.push(`${err}, ${msg}`); 28 | return; 29 | } 30 | global.ipcCalls.push(`${msg}`); 31 | }); 32 | 33 | ipcPlus.sendToWin(win, 'app:hello', 'cell', (err, msg) => { 34 | if ( err ) { 35 | global.ipcCalls.push(`${err}, ${msg}`); 36 | return; 37 | } 38 | global.ipcCalls.push(`${msg}`); 39 | }); 40 | } 41 | 42 | app.on('ready', function () { 43 | win = new BrowserWindow({ 44 | x: 100 + 210, 45 | y: 100, 46 | width: 200, 47 | height: 200 48 | }); 49 | win.loadURL('file://' + __dirname + '/index.html'); 50 | win.webContents.once('dom-ready', domReady); 51 | }); 52 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-more-than-once/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-nested/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-nested/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | // win0 15 | ipcPlus.sendToWin(wins[0], 'app:hello', (err, msg) => { 16 | if ( err ) { 17 | global.ipcCalls.push(`${err}, ${msg}`); 18 | return; 19 | } 20 | global.ipcCalls.push(`${msg}`); 21 | 22 | ipcPlus.sendToWin(wins[0], 'app:hello-nested', (err, msg) => { 23 | if ( err ) { 24 | global.ipcCalls.push(`${err}, ${msg}`); 25 | return; 26 | } 27 | global.ipcCalls.push(`${msg}`); 28 | }); 29 | }); 30 | ipcPlus.sendToWin(wins[0], 'app:hello', 'alpha', (err, msg) => { 31 | if ( err ) { 32 | global.ipcCalls.push(`${err}, ${msg}`); 33 | return; 34 | } 35 | global.ipcCalls.push(`${msg}`); 36 | 37 | ipcPlus.sendToWin(wins[0], 'app:hello-nested', 'alpha-nested', (err, msg) => { 38 | if ( err ) { 39 | global.ipcCalls.push(`${err}, ${msg}`); 40 | return; 41 | } 42 | global.ipcCalls.push(`${msg}`); 43 | }); 44 | }); 45 | 46 | // win1 47 | setTimeout(() => { 48 | ipcPlus.sendToWin(wins[1], 'app:hello', (err, msg) => { 49 | if ( err ) { 50 | global.ipcCalls.push(`${err}, ${msg}`); 51 | return; 52 | } 53 | global.ipcCalls.push(`${msg}`); 54 | 55 | ipcPlus.sendToWin(wins[1], 'app:hello-nested', (err, msg) => { 56 | if ( err ) { 57 | global.ipcCalls.push(`${err}, ${msg}`); 58 | return; 59 | } 60 | global.ipcCalls.push(`${msg}`); 61 | }); 62 | }); 63 | ipcPlus.sendToWin(wins[1], 'app:hello', 'beta', (err, msg) => { 64 | if ( err ) { 65 | global.ipcCalls.push(`${err}, ${msg}`); 66 | return; 67 | } 68 | global.ipcCalls.push(`${msg}`); 69 | 70 | ipcPlus.sendToWin(wins[1], 'app:hello-nested', 'beta-nested', (err, msg) => { 71 | if ( err ) { 72 | global.ipcCalls.push(`${err}, ${msg}`); 73 | return; 74 | } 75 | global.ipcCalls.push(`${msg}`); 76 | }); 77 | }); 78 | }, 100); 79 | 80 | // win2 81 | setTimeout(() => { 82 | ipcPlus.sendToWin(wins[2], 'app:hello', (err, msg) => { 83 | if ( err ) { 84 | global.ipcCalls.push(`${err}, ${msg}`); 85 | return; 86 | } 87 | global.ipcCalls.push(`${msg}`); 88 | 89 | ipcPlus.sendToWin(wins[2], 'app:hello-nested', (err, msg) => { 90 | if ( err ) { 91 | global.ipcCalls.push(`${err}, ${msg}`); 92 | return; 93 | } 94 | global.ipcCalls.push(`${msg}`); 95 | }); 96 | }); 97 | ipcPlus.sendToWin(wins[2], 'app:hello', 'cell', (err, msg) => { 98 | if ( err ) { 99 | global.ipcCalls.push(`${err}, ${msg}`); 100 | return; 101 | } 102 | global.ipcCalls.push(`${msg}`); 103 | 104 | ipcPlus.sendToWin(wins[2], 'app:hello-nested', 'cell-nested', (err, msg) => { 105 | if ( err ) { 106 | global.ipcCalls.push(`${err}, ${msg}`); 107 | return; 108 | } 109 | global.ipcCalls.push(`${msg}`); 110 | }); 111 | }); 112 | }, 200); 113 | } 114 | } 115 | 116 | app.on('ready', function () { 117 | for ( let i = 0; i < maxWins; ++i ) { 118 | let win = new BrowserWindow({ 119 | x: 100 + 210*i, 120 | y: 100, 121 | width: 200, 122 | height: 200 123 | }); 124 | win.loadURL('file://' + __dirname + '/index.html'); 125 | win.webContents.once('dom-ready', domReady); 126 | 127 | wins.push(win); 128 | } 129 | }); 130 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-nested/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-timeout/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-timeout/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let win; 7 | 8 | function domReady () { 9 | ipcPlus.sendToWin(win, 'app:hello', (err, msg) => { 10 | if ( err && err.code === 'ETIMEDOUT' ) { 11 | global.ipcCalls.push('timeout'); 12 | return; 13 | } 14 | global.ipcCalls.push(`${msg}`); 15 | }, 100); 16 | 17 | ipcPlus.sendToWin(win, 'app:hello', 'alpha', (err, msg) => { 18 | if ( err && err.code === 'ETIMEDOUT' ) { 19 | global.ipcCalls.push(`timeout alpha`); 20 | return; 21 | } 22 | global.ipcCalls.push(`${msg}`); 23 | }, 100); 24 | 25 | ipcPlus.sendToWin(win, 'app:hello', 'beta', (err, msg) => { 26 | if ( err && err.code === 'ETIMEDOUT' ) { 27 | global.ipcCalls.push(`timeout beta`); 28 | return; 29 | } 30 | global.ipcCalls.push(`${msg}`); 31 | }, 100); 32 | 33 | ipcPlus.sendToWin(win, 'app:hello', 'cell', (err, msg) => { 34 | if ( err && err.code === 'ETIMEDOUT' ) { 35 | global.ipcCalls.push(`timeout cell`); 36 | return; 37 | } 38 | global.ipcCalls.push(`${msg}`); 39 | }, 400); 40 | } 41 | 42 | app.on('ready', function () { 43 | win = new BrowserWindow({ 44 | x: 100 + 210, 45 | y: 100, 46 | width: 200, 47 | height: 200 48 | }); 49 | win.loadURL('file://' + __dirname + '/index.html'); 50 | win.webContents.once('dom-ready', domReady); 51 | }); 52 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply-timeout/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | // win0 15 | ipcPlus.sendToWin(wins[0], 'app:hello', (err, msg) => { 16 | if ( err ) { 17 | global.ipcCalls.push(`${err}, ${msg}`); 18 | return; 19 | } 20 | global.ipcCalls.push(`${msg}`); 21 | }); 22 | ipcPlus.sendToWin(wins[0], 'app:hello', 'alpha', (err, msg) => { 23 | if ( err ) { 24 | global.ipcCalls.push(`${err}, ${msg}`); 25 | return; 26 | } 27 | global.ipcCalls.push(`${msg}`); 28 | }); 29 | 30 | // win1 31 | setTimeout(() => { 32 | ipcPlus.sendToWin(wins[1], 'app:hello', (err, msg) => { 33 | if ( err ) { 34 | global.ipcCalls.push(`${err}, ${msg}`); 35 | return; 36 | } 37 | global.ipcCalls.push(`${msg}`); 38 | }); 39 | ipcPlus.sendToWin(wins[1], 'app:hello', 'beta', (err, msg) => { 40 | if ( err ) { 41 | global.ipcCalls.push(`${err}, ${msg}`); 42 | return; 43 | } 44 | global.ipcCalls.push(`${msg}`); 45 | }); 46 | }, 100); 47 | 48 | // win2 49 | setTimeout(() => { 50 | ipcPlus.sendToWin(wins[2], 'app:hello', (err, msg) => { 51 | if ( err ) { 52 | global.ipcCalls.push(`${err}, ${msg}`); 53 | return; 54 | } 55 | global.ipcCalls.push(`${msg}`); 56 | }); 57 | ipcPlus.sendToWin(wins[2], 'app:hello', 'cell', (err, msg) => { 58 | if ( err ) { 59 | global.ipcCalls.push(`${err}, ${msg}`); 60 | return; 61 | } 62 | global.ipcCalls.push(`${msg}`); 63 | }); 64 | }, 200); 65 | } 66 | } 67 | 68 | app.on('ready', function () { 69 | for ( let i = 0; i < maxWins; ++i ) { 70 | let win = new BrowserWindow({ 71 | x: 100 + 210*i, 72 | y: 100, 73 | width: 200, 74 | height: 200 75 | }); 76 | win.loadURL('file://' + __dirname + '/index.html'); 77 | win.webContents.once('dom-ready', domReady); 78 | 79 | wins.push(win); 80 | } 81 | }); 82 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win-reply/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | ipcPlus.sendToWin(wins[0], 'app:hello'); 15 | ipcPlus.sendToWin(wins[0], 'app:hello', 'alpha'); 16 | 17 | ipcPlus.sendToWin(wins[1], 'app:hello'); 18 | ipcPlus.sendToWin(wins[1], 'app:hello', 'beta'); 19 | 20 | ipcPlus.sendToWin(wins[2], 'app:hello'); 21 | ipcPlus.sendToWin(wins[2], 'app:hello', 'cell'); 22 | } 23 | } 24 | 25 | app.on('ready', function () { 26 | for ( let i = 0; i < maxWins; ++i ) { 27 | let win = new BrowserWindow({ 28 | x: 100 + 210*i, 29 | y: 100, 30 | width: 200, 31 | height: 200 32 | }); 33 | win.loadURL('file://' + __dirname + '/index.html'); 34 | win.webContents.once('dom-ready', domReady); 35 | 36 | wins.push(win); 37 | } 38 | }); 39 | 40 | ipcPlus.on('app:hello', (event, ...args) => { 41 | global.ipcCalls.push(`app:hello ${args}`); 42 | }); 43 | -------------------------------------------------------------------------------- /test/fixtures/app-main2win/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-main2wins/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/app-main2wins/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | ipcPlus.sendToWins('app:hello'); 15 | ipcPlus.sendToWins('app:hello', 'alpha'); 16 | ipcPlus.sendToWins('app:hello', 'beta'); 17 | ipcPlus.sendToWins('app:hello', 'cell'); 18 | } 19 | } 20 | 21 | app.on('ready', function () { 22 | for ( let i = 0; i < maxWins; ++i ) { 23 | let win = new BrowserWindow({ 24 | x: 100 + 210*i, 25 | y: 100, 26 | width: 200, 27 | height: 200 28 | }); 29 | win.loadURL('file://' + __dirname + '/index.html'); 30 | win.webContents.once('dom-ready', domReady); 31 | 32 | wins.push(win); 33 | } 34 | }); 35 | 36 | ipcPlus.on('app:hello', (event, ...args) => { 37 | global.ipcCalls.push(`app:hello ${args}`); 38 | }); 39 | -------------------------------------------------------------------------------- /test/fixtures/app-main2wins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2all-exclude-self/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/app-win2all-exclude-self/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | ipcPlus.sendToAll('app:all-windows-ready'); 15 | } 16 | } 17 | 18 | app.on('ready', function () { 19 | let i = 0; 20 | let mainWin = new BrowserWindow({ 21 | x: 100 + 210*i, 22 | y: 100, 23 | width: 200, 24 | height: 200 25 | }); 26 | mainWin.loadURL('file://' + __dirname + '/send.html'); 27 | mainWin.webContents.once('dom-ready', domReady); 28 | 29 | wins.push(mainWin); 30 | 31 | for ( i = 1; i < maxWins; ++i ) { 32 | let win = new BrowserWindow({ 33 | x: 100 + 210*i, 34 | y: 100, 35 | width: 200, 36 | height: 200 37 | }); 38 | win.loadURL('file://' + __dirname + '/index.html'); 39 | win.webContents.once('dom-ready', domReady); 40 | 41 | wins.push(win); 42 | } 43 | }); 44 | 45 | ipcPlus.on('app:hello', (event, ...args) => { 46 | global.ipcCalls.push(`app:hello ${args}`); 47 | }); 48 | -------------------------------------------------------------------------------- /test/fixtures/app-win2all-exclude-self/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2all-exclude-self/send.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/fixtures/app-win2all/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/app-win2all/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | ipcPlus.sendToAll('app:all-windows-ready'); 15 | } 16 | } 17 | 18 | app.on('ready', function () { 19 | let i = 0; 20 | let mainWin = new BrowserWindow({ 21 | x: 100 + 210*i, 22 | y: 100, 23 | width: 200, 24 | height: 200 25 | }); 26 | mainWin.loadURL('file://' + __dirname + '/send.html'); 27 | mainWin.webContents.once('dom-ready', domReady); 28 | 29 | wins.push(mainWin); 30 | 31 | for ( i = 1; i < maxWins; ++i ) { 32 | let win = new BrowserWindow({ 33 | x: 100 + 210*i, 34 | y: 100, 35 | width: 200, 36 | height: 200 37 | }); 38 | win.loadURL('file://' + __dirname + '/index.html'); 39 | win.webContents.once('dom-ready', domReady); 40 | 41 | wins.push(win); 42 | } 43 | }); 44 | 45 | ipcPlus.on('app:hello', (event, ...args) => { 46 | global.ipcCalls.push(`app:hello ${args}`); 47 | }); 48 | -------------------------------------------------------------------------------- /test/fixtures/app-win2all/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2all/send.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-a-user-error/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-a-user-error/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | }); 15 | 16 | ipcPlus.on('app:hello', (event, ...args) => { 17 | global.ipcCalls.push(`app:hello ${args}`); 18 | event.reply(new Error(`user`), `${args} failed`); 19 | }); 20 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-a-user-error/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-cancel-request/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-cancel-request/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | }); 15 | 16 | ipcPlus.on('app:hello', (event, ...args) => { 17 | global.ipcCalls.push(`app:hello ${args}`); 18 | setTimeout(() => { 19 | event.reply(null, `${args} received`); 20 | }, 200); 21 | }); 22 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-cancel-request/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-error-no-callback/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-error-no-callback/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | }); 15 | 16 | ipcPlus.on('app:hello', (event, ...args) => { 17 | global.ipcCalls.push(`app:hello ${args}`); 18 | if ( event.reply ) { 19 | global.ipcCalls.push(`${args} replied`); 20 | event.reply(null, `${args} received`); 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-error-no-callback/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-error-win-destroyed/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-error-win-destroyed/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-error-win-destroyed/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let win, win2; 7 | app.on('ready', function () { 8 | win = new BrowserWindow({ 9 | x: 300, 10 | y: 100, 11 | width: 200, 12 | height: 200 13 | }); 14 | win.loadURL('file://' + __dirname + '/index.html'); 15 | 16 | win2 = new BrowserWindow({ 17 | x: 300 + 210, 18 | y: 100, 19 | width: 200, 20 | height: 200 21 | }); 22 | win2.loadURL('file://' + __dirname + '/index2.html'); 23 | }); 24 | 25 | ipcPlus.on('app:hello', (event, ...args) => { 26 | win.close(); 27 | 28 | global.ipcCalls.push(`app:hello ${args}`); 29 | setTimeout(() => { 30 | event.reply(null, `${args} received`); 31 | }, 300); 32 | }); 33 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-error-win-destroyed/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-invalid-first-arg/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-invalid-first-arg/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | }); 15 | 16 | ipcPlus.on('app:hello', (event, ...args) => { 17 | global.ipcCalls.push(`app:hello ${args}`); 18 | event.reply(`${args} received`); // NOTE: first argument invalid 19 | }); 20 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-invalid-first-arg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-more-than-once/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-more-than-once/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | }); 15 | 16 | ipcPlus.on('app:hello', (event, ...args) => { 17 | global.ipcCalls.push(`app:hello ${args}`); 18 | event.reply(null, `${args} received`); 19 | event.reply(null, `${args} received 02`); 20 | }); 21 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-more-than-once/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-nested/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-nested/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | }); 15 | 16 | ipcPlus.on('app:hello', (event, ...args) => { 17 | global.ipcCalls.push(`app:hello ${args}`); 18 | event.reply(null, `${args} received`); 19 | }); 20 | 21 | ipcPlus.on('app:hello-nested', (event, ...args) => { 22 | global.ipcCalls.push(`app:hello-nested ${args}`); 23 | event.reply(null, `${args} received`); 24 | }); 25 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-nested/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-timeout/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-timeout/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | }); 15 | 16 | ipcPlus.on('app:hello', (event, ...args) => { 17 | global.ipcCalls.push(`app:hello ${args}`); 18 | setTimeout(() => { 19 | event.reply(null, `${args} received`); 20 | }, 200); 21 | }); 22 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply-timeout/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | }); 15 | 16 | ipcPlus.on('app:hello', (event, ...args) => { 17 | global.ipcCalls.push(`app:hello ${args}`); 18 | event.reply(null, `${args} received`); 19 | }); 20 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main-reply/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | app.on('ready', function () { 7 | let win = new BrowserWindow({ 8 | x: 300, 9 | y: 100, 10 | width: 200, 11 | height: 200 12 | }); 13 | win.loadURL('file://' + __dirname + '/index.html'); 14 | }); 15 | 16 | ipcPlus.on('app:hello', (event, ...args) => { 17 | global.ipcCalls.push(`app:hello ${args}`); 18 | }); 19 | -------------------------------------------------------------------------------- /test/fixtures/app-win2main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2wins-exclude-self/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/app-win2wins-exclude-self/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | ipcPlus.sendToAll('app:all-windows-ready'); 15 | } 16 | } 17 | 18 | app.on('ready', function () { 19 | let i = 0; 20 | let mainWin = new BrowserWindow({ 21 | x: 100 + 210*i, 22 | y: 100, 23 | width: 200, 24 | height: 200 25 | }); 26 | mainWin.loadURL('file://' + __dirname + '/send.html'); 27 | mainWin.webContents.once('dom-ready', domReady); 28 | 29 | wins.push(mainWin); 30 | 31 | for ( i = 1; i < maxWins; ++i ) { 32 | let win = new BrowserWindow({ 33 | x: 100 + 210*i, 34 | y: 100, 35 | width: 200, 36 | height: 200 37 | }); 38 | win.loadURL('file://' + __dirname + '/index.html'); 39 | win.webContents.once('dom-ready', domReady); 40 | 41 | wins.push(win); 42 | } 43 | }); 44 | 45 | ipcPlus.on('app:hello', (event, ...args) => { 46 | global.ipcCalls.push(`app:hello ${args}`); 47 | }); 48 | -------------------------------------------------------------------------------- /test/fixtures/app-win2wins-exclude-self/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2wins-exclude-self/send.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/fixtures/app-win2wins/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/app-win2wins/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electron'); 2 | const ipcPlus = require('../../../index.js'); 3 | 4 | global.ipcCalls = []; 5 | 6 | let readyCnt = 0; 7 | let maxWins = 3; 8 | let wins = []; 9 | 10 | function domReady () { 11 | ++readyCnt; 12 | 13 | if ( readyCnt === maxWins ) { 14 | ipcPlus.sendToAll('app:all-windows-ready'); 15 | } 16 | } 17 | 18 | app.on('ready', function () { 19 | let i = 0; 20 | let mainWin = new BrowserWindow({ 21 | x: 100 + 210*i, 22 | y: 100, 23 | width: 200, 24 | height: 200 25 | }); 26 | mainWin.loadURL('file://' + __dirname + '/send.html'); 27 | mainWin.webContents.once('dom-ready', domReady); 28 | 29 | wins.push(mainWin); 30 | 31 | for ( i = 1; i < maxWins; ++i ) { 32 | let win = new BrowserWindow({ 33 | x: 100 + 210*i, 34 | y: 100, 35 | width: 200, 36 | height: 200 37 | }); 38 | win.loadURL('file://' + __dirname + '/index.html'); 39 | win.webContents.once('dom-ready', domReady); 40 | 41 | wins.push(win); 42 | } 43 | }); 44 | 45 | ipcPlus.on('app:hello', (event, ...args) => { 46 | global.ipcCalls.push(`app:hello ${args}`); 47 | }); 48 | -------------------------------------------------------------------------------- /test/fixtures/app-win2wins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/app-win2wins/send.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Electron App 6 | 7 | 8 | 9 |
Testing...
10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/send-to-all.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const electron = require('electron'); 5 | const {Application} = require('spectron'); 6 | const assert = require('assert'); 7 | 8 | describe('app-main2all', function () { 9 | this.timeout(0); 10 | let app = null; 11 | 12 | before(function () { 13 | app = new Application({ 14 | path: electron, 15 | args: [path.join(__dirname, 'fixtures', 'app-main2all')] 16 | }); 17 | return app.start(); 18 | }); 19 | 20 | after(function () { 21 | if (app && app.isRunning()) { 22 | return app.stop(); 23 | } 24 | }); 25 | 26 | it('should be ok', function () { 27 | return app.client 28 | .windowByIndex(0) 29 | .waitUntilWindowLoaded() 30 | .getRenderProcessLogs() 31 | .then(function (logs) { 32 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 33 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 34 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 35 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 36 | 37 | return app.client 38 | .windowByIndex(1) 39 | .waitUntilWindowLoaded() 40 | .getRenderProcessLogs() 41 | .then(function (logs) { 42 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 43 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 44 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 45 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 46 | 47 | return app.client 48 | .windowByIndex(2) 49 | .waitUntilWindowLoaded() 50 | .getRenderProcessLogs() 51 | .then(function (logs) { 52 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 53 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 54 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 55 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 56 | 57 | return app.electron.remote.getGlobal('ipcCalls') 58 | .then(function (ipcCalls) { 59 | assert.equal(ipcCalls.length, 4); 60 | assert.equal(ipcCalls[0], 'app:hello '); 61 | assert.equal(ipcCalls[1], 'app:hello alpha'); 62 | assert.equal(ipcCalls[2], 'app:hello beta'); 63 | assert.equal(ipcCalls[3], 'app:hello cell'); 64 | }); 65 | }); 66 | }); 67 | }); 68 | }); 69 | }); 70 | 71 | describe('app-main2all-exclude-self', function () { 72 | this.timeout(0); 73 | let app = null; 74 | 75 | before(function () { 76 | app = new Application({ 77 | path: electron, 78 | args: [path.join(__dirname, 'fixtures', 'app-main2all-exclude-self')] 79 | }); 80 | return app.start(); 81 | }); 82 | 83 | after(function () { 84 | if (app && app.isRunning()) { 85 | return app.stop(); 86 | } 87 | }); 88 | 89 | it('should be ok', function () { 90 | return app.client 91 | .windowByIndex(0) 92 | .waitUntilWindowLoaded() 93 | .getRenderProcessLogs() 94 | .then(function (logs) { 95 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 96 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 97 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 98 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 99 | 100 | return app.client 101 | .windowByIndex(1) 102 | .waitUntilWindowLoaded() 103 | .getRenderProcessLogs() 104 | .then(function (logs) { 105 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 106 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 107 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 108 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 109 | 110 | return app.client 111 | .windowByIndex(2) 112 | .waitUntilWindowLoaded() 113 | .getRenderProcessLogs() 114 | .then(function (logs) { 115 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 116 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 117 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 118 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 119 | 120 | return app.electron.remote.getGlobal('ipcCalls') 121 | .then(function (ipcCalls) { 122 | assert.equal(ipcCalls.length, 0); 123 | }); 124 | }); 125 | }); 126 | }); 127 | }); 128 | }); 129 | 130 | describe('app-win2all', function () { 131 | this.timeout(0); 132 | let app = null; 133 | 134 | before(function () { 135 | app = new Application({ 136 | path: electron, 137 | args: [path.join(__dirname, 'fixtures', 'app-win2all')] 138 | }); 139 | return app.start(); 140 | }); 141 | 142 | after(function () { 143 | if (app && app.isRunning()) { 144 | return app.stop(); 145 | } 146 | }); 147 | 148 | it('should be ok', function () { 149 | return app.client 150 | .windowByIndex(0) 151 | .waitUntilWindowLoaded() 152 | .getRenderProcessLogs() 153 | .then(function (logs) { 154 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 155 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 156 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 157 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 158 | 159 | return app.client 160 | .windowByIndex(1) 161 | .waitUntilWindowLoaded() 162 | .getRenderProcessLogs() 163 | .then(function (logs) { 164 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 165 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 166 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 167 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 168 | 169 | return app.client 170 | .windowByIndex(2) 171 | .waitUntilWindowLoaded() 172 | .getRenderProcessLogs() 173 | .then(function (logs) { 174 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 175 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 176 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 177 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 178 | 179 | return app.electron.remote.getGlobal('ipcCalls') 180 | .then(function (ipcCalls) { 181 | assert.equal(ipcCalls.length, 4); 182 | assert.equal(ipcCalls[0], 'app:hello '); 183 | assert.equal(ipcCalls[1], 'app:hello alpha'); 184 | assert.equal(ipcCalls[2], 'app:hello beta'); 185 | assert.equal(ipcCalls[3], 'app:hello cell'); 186 | }); 187 | }); 188 | }); 189 | }); 190 | }); 191 | }); 192 | 193 | 194 | describe('app-win2all-exclude-self', function () { 195 | this.timeout(0); 196 | let app = null; 197 | 198 | before(function () { 199 | app = new Application({ 200 | path: electron, 201 | args: [path.join(__dirname, 'fixtures', 'app-win2all-exclude-self')] 202 | }); 203 | return app.start(); 204 | }); 205 | 206 | after(function () { 207 | if (app && app.isRunning()) { 208 | return app.stop(); 209 | } 210 | }); 211 | 212 | it('should be ok', function () { 213 | return app.client 214 | .windowByIndex(0) 215 | .waitUntilWindowLoaded() 216 | .getRenderProcessLogs() 217 | .then(function (logs) { 218 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 219 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 220 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 221 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 222 | 223 | return app.client 224 | .windowByIndex(1) 225 | .waitUntilWindowLoaded() 226 | .getRenderProcessLogs() 227 | .then(function (logs) { 228 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 229 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 230 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 231 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 232 | 233 | return app.client 234 | .windowByIndex(2) 235 | .waitUntilWindowLoaded() 236 | .getRenderProcessLogs() 237 | .then(function (logs) { 238 | assert.equal(logs.length, 0); 239 | 240 | return app.electron.remote.getGlobal('ipcCalls') 241 | .then(function (ipcCalls) { 242 | assert.equal(ipcCalls.length, 4); 243 | assert.equal(ipcCalls[0], 'app:hello '); 244 | assert.equal(ipcCalls[1], 'app:hello alpha'); 245 | assert.equal(ipcCalls[2], 'app:hello beta'); 246 | assert.equal(ipcCalls[3], 'app:hello cell'); 247 | }); 248 | }); 249 | }); 250 | }); 251 | }); 252 | }); 253 | -------------------------------------------------------------------------------- /test/send-to-main-reply.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const electron = require('electron'); 5 | const {Application} = require('spectron'); 6 | const assert = require('assert'); 7 | 8 | describe('app-win2main-reply', function () { 9 | this.timeout(0); 10 | let app = null; 11 | 12 | before(function () { 13 | app = new Application({ 14 | path: electron, 15 | args: [path.join(__dirname, 'fixtures', 'app-win2main-reply')] 16 | }); 17 | return app.start(); 18 | }); 19 | 20 | after(function () { 21 | if (app && app.isRunning()) { 22 | return app.stop(); 23 | } 24 | }); 25 | 26 | it('should be ok', function () { 27 | return app.client 28 | .windowByIndex(0) 29 | .waitUntilWindowLoaded() 30 | .getRenderProcessLogs() 31 | .then(function (logs) { 32 | assert.equal(logs.length, 4); 33 | assert.ok(logs[0].message.indexOf(' received') !== -1); 34 | assert.ok(logs[1].message.indexOf('alpha received') !== -1); 35 | assert.ok(logs[2].message.indexOf('beta received') !== -1); 36 | assert.ok(logs[3].message.indexOf('cell received') !== -1); 37 | 38 | return app.electron.remote.getGlobal('ipcCalls') 39 | .then(function (ipcCalls) { 40 | assert.equal(ipcCalls.length, 4); 41 | assert.equal(ipcCalls[0], 'app:hello '); 42 | assert.equal(ipcCalls[1], 'app:hello alpha'); 43 | assert.equal(ipcCalls[2], 'app:hello beta'); 44 | assert.equal(ipcCalls[3], 'app:hello cell'); 45 | }); 46 | }); 47 | }); 48 | }); 49 | 50 | describe('app-win2main-reply-nested', function () { 51 | this.timeout(0); 52 | let app = null; 53 | 54 | before(function () { 55 | app = new Application({ 56 | path: electron, 57 | args: [path.join(__dirname, 'fixtures', 'app-win2main-reply-nested')] 58 | }); 59 | return app.start(); 60 | }); 61 | 62 | after(function () { 63 | if (app && app.isRunning()) { 64 | return app.stop(); 65 | } 66 | }); 67 | 68 | it('should be ok', function () { 69 | return app.client 70 | .windowByIndex(0) 71 | .waitUntilTextExists('.label', 'Ready') 72 | .getRenderProcessLogs() 73 | .then(function (logs) { 74 | assert.equal(logs.length, 8); 75 | assert.ok(logs[0].message.indexOf(' received') !== -1); 76 | assert.ok(logs[1].message.indexOf('alpha received') !== -1); 77 | assert.ok(logs[2].message.indexOf('beta received') !== -1); 78 | assert.ok(logs[3].message.indexOf('cell received') !== -1); 79 | assert.ok(logs[4].message.indexOf(' received received') !== -1); 80 | assert.ok(logs[5].message.indexOf('alpha received received') !== -1); 81 | assert.ok(logs[6].message.indexOf('beta received received') !== -1); 82 | assert.ok(logs[7].message.indexOf('cell received received') !== -1); 83 | 84 | return app.electron.remote.getGlobal('ipcCalls') 85 | .then(function (ipcCalls) { 86 | assert.equal(ipcCalls.length, 8); 87 | assert.equal(ipcCalls[0], 'app:hello '); 88 | assert.equal(ipcCalls[1], 'app:hello alpha'); 89 | assert.equal(ipcCalls[2], 'app:hello beta'); 90 | assert.equal(ipcCalls[3], 'app:hello cell'); 91 | assert.equal(ipcCalls[4], 'app:hello-nested received'); 92 | assert.equal(ipcCalls[5], 'app:hello-nested alpha received'); 93 | assert.equal(ipcCalls[6], 'app:hello-nested beta received'); 94 | assert.equal(ipcCalls[7], 'app:hello-nested cell received'); 95 | }); 96 | }); 97 | }); 98 | }); 99 | 100 | describe('app-win2main-reply-more-than-once', function () { 101 | this.timeout(0); 102 | let app = null; 103 | 104 | before(function () { 105 | app = new Application({ 106 | path: electron, 107 | args: [path.join(__dirname, 'fixtures', 'app-win2main-reply-more-than-once')] 108 | }); 109 | return app.start(); 110 | }); 111 | 112 | after(function () { 113 | if (app && app.isRunning()) { 114 | return app.stop(); 115 | } 116 | }); 117 | 118 | it('should be ok', function () { 119 | return app.client 120 | .windowByIndex(0) 121 | .waitUntilWindowLoaded() 122 | .getRenderProcessLogs() 123 | .then(function (logs) { 124 | assert.equal(logs.length, 4); 125 | assert.ok(logs[0].message.indexOf(' received') !== -1); 126 | assert.ok(logs[1].message.indexOf('alpha received') !== -1); 127 | assert.ok(logs[2].message.indexOf('beta received') !== -1); 128 | assert.ok(logs[3].message.indexOf('cell received') !== -1); 129 | 130 | return app.electron.remote.getGlobal('ipcCalls') 131 | .then(function (ipcCalls) { 132 | assert.equal(ipcCalls.length, 4); 133 | assert.equal(ipcCalls[0], 'app:hello '); 134 | assert.equal(ipcCalls[1], 'app:hello alpha'); 135 | assert.equal(ipcCalls[2], 'app:hello beta'); 136 | assert.equal(ipcCalls[3], 'app:hello cell'); 137 | }); 138 | }); 139 | }); 140 | }); 141 | 142 | describe('app-win2main-reply-error-timeout', function () { 143 | this.timeout(0); 144 | let app = null; 145 | 146 | before(function () { 147 | app = new Application({ 148 | path: electron, 149 | args: [path.join(__dirname, 'fixtures', 'app-win2main-reply-timeout')] 150 | }); 151 | return app.start(); 152 | }); 153 | 154 | after(function () { 155 | if (app && app.isRunning()) { 156 | return app.stop(); 157 | } 158 | }); 159 | 160 | it('should be ok', function () { 161 | return app.client 162 | .windowByIndex(0) 163 | .waitUntilTextExists('.label', 'Ready') 164 | .getRenderProcessLogs() 165 | .then(function (logs) { 166 | assert.equal(logs.length, 4); 167 | assert.ok(logs[0].message.indexOf('timeout') !== -1); 168 | assert.ok(logs[1].message.indexOf('timeout alpha') !== -1); 169 | assert.ok(logs[2].message.indexOf('timeout beta') !== -1); 170 | assert.ok(logs[3].message.indexOf('cell received') !== -1); 171 | 172 | return app.electron.remote.getGlobal('ipcCalls') 173 | .then(function (ipcCalls) { 174 | assert.equal(ipcCalls.length, 4); 175 | assert.equal(ipcCalls[0], 'app:hello '); 176 | assert.equal(ipcCalls[1], 'app:hello alpha'); 177 | assert.equal(ipcCalls[2], 'app:hello beta'); 178 | assert.equal(ipcCalls[3], 'app:hello cell'); 179 | }); 180 | }); 181 | }); 182 | }); 183 | 184 | describe('app-win2main-reply-cancel-request', function () { 185 | this.timeout(0); 186 | let app = null; 187 | 188 | before(function () { 189 | app = new Application({ 190 | path: electron, 191 | args: [path.join(__dirname, 'fixtures', 'app-win2main-reply-cancel-request')] 192 | }); 193 | return app.start(); 194 | }); 195 | 196 | after(function () { 197 | if (app && app.isRunning()) { 198 | return app.stop(); 199 | } 200 | }); 201 | 202 | it('should be ok', function () { 203 | return app.client 204 | .windowByIndex(0) 205 | .waitUntilTextExists('.label', 'Ready') 206 | .getRenderProcessLogs() 207 | .then(function (logs) { 208 | assert.equal(logs.length, 0); 209 | 210 | return app.electron.remote.getGlobal('ipcCalls') 211 | .then(function (ipcCalls) { 212 | assert.equal(ipcCalls.length, 4); 213 | assert.equal(ipcCalls[0], 'app:hello '); 214 | assert.equal(ipcCalls[1], 'app:hello alpha'); 215 | assert.equal(ipcCalls[2], 'app:hello beta'); 216 | assert.equal(ipcCalls[3], 'app:hello cell'); 217 | }); 218 | }); 219 | }); 220 | }); 221 | 222 | describe('app-win2main-reply-error-win-destroyed', function () { 223 | this.timeout(0); 224 | let app = null; 225 | 226 | before(function () { 227 | app = new Application({ 228 | path: electron, 229 | args: [path.join(__dirname, 'fixtures', 'app-win2main-reply-error-win-destroyed')] 230 | }); 231 | return app.start(); 232 | }); 233 | 234 | after(function () { 235 | if (app && app.isRunning()) { 236 | return app.stop(); 237 | } 238 | }); 239 | 240 | it('should be ok', function () { 241 | return app.client 242 | .windowByIndex(0) // NOTE: yes, should be index-0, not index-1 243 | .waitUntilTextExists('.label', 'Ready') 244 | .then(function () { 245 | return app.electron.remote.getGlobal('ipcCalls') 246 | .then(function (ipcCalls) { 247 | assert.equal(ipcCalls.length, 1); 248 | assert.equal(ipcCalls[0], 'app:hello foobar'); 249 | }); 250 | }); 251 | }); 252 | }); 253 | 254 | describe('app-win2main-reply-error-no-callback', function () { 255 | this.timeout(0); 256 | let app = null; 257 | 258 | before(function () { 259 | app = new Application({ 260 | path: electron, 261 | args: [path.join(__dirname, 'fixtures', 'app-win2main-reply-error-no-callback')] 262 | }); 263 | return app.start(); 264 | }); 265 | 266 | after(function () { 267 | if (app && app.isRunning()) { 268 | return app.stop(); 269 | } 270 | }); 271 | 272 | it('should be ok', function () { 273 | return app.client 274 | .windowByIndex(0) 275 | .waitUntilWindowLoaded() 276 | .getRenderProcessLogs() 277 | .then(function (logs) { 278 | assert.equal(logs.length, 0); 279 | 280 | return app.electron.remote.getGlobal('ipcCalls') 281 | .then(function (ipcCalls) { 282 | assert.equal(ipcCalls.length, 4); 283 | assert.equal(ipcCalls[0], 'app:hello '); 284 | assert.equal(ipcCalls[1], 'app:hello alpha'); 285 | assert.equal(ipcCalls[2], 'app:hello beta'); 286 | assert.equal(ipcCalls[3], 'app:hello cell'); 287 | }); 288 | }); 289 | }); 290 | }); 291 | 292 | describe('app-win2main-reply-a-user-error', function () { 293 | this.timeout(0); 294 | let app = null; 295 | 296 | before(function () { 297 | app = new Application({ 298 | path: electron, 299 | args: [path.join(__dirname, 'fixtures', 'app-win2main-reply-a-user-error')] 300 | }); 301 | return app.start(); 302 | }); 303 | 304 | after(function () { 305 | if (app && app.isRunning()) { 306 | return app.stop(); 307 | } 308 | }); 309 | 310 | it('should be ok', function () { 311 | return app.client 312 | .windowByIndex(0) 313 | .waitUntilWindowLoaded() 314 | .getRenderProcessLogs() 315 | .then(function (logs) { 316 | assert.equal(logs.length, 4); 317 | assert.ok(logs[0].message.indexOf('Error: user, failed') !== -1); 318 | assert.ok(logs[1].message.indexOf('Error: user, alpha failed') !== -1); 319 | assert.ok(logs[2].message.indexOf('Error: user, beta failed') !== -1); 320 | assert.ok(logs[3].message.indexOf('Error: user, cell failed') !== -1); 321 | 322 | return app.electron.remote.getGlobal('ipcCalls') 323 | .then(function (ipcCalls) { 324 | assert.equal(ipcCalls.length, 4); 325 | assert.equal(ipcCalls[0], 'app:hello '); 326 | assert.equal(ipcCalls[1], 'app:hello alpha'); 327 | assert.equal(ipcCalls[2], 'app:hello beta'); 328 | assert.equal(ipcCalls[3], 'app:hello cell'); 329 | }); 330 | }); 331 | }); 332 | }); 333 | 334 | describe('app-win2main-reply-error-invalid-first-arg', function () { 335 | this.timeout(0); 336 | let app = null; 337 | 338 | before(function () { 339 | app = new Application({ 340 | path: electron, 341 | args: [path.join(__dirname, 'fixtures', 'app-win2main-reply-invalid-first-arg')] 342 | }); 343 | return app.start(); 344 | }); 345 | 346 | after(function () { 347 | if (app && app.isRunning()) { 348 | return app.stop(); 349 | } 350 | }); 351 | 352 | it('should be ok', function () { 353 | return app.client 354 | .windowByIndex(0) 355 | .waitUntilWindowLoaded() 356 | .getRenderProcessLogs() 357 | .then(function (logs) { 358 | assert.equal(logs.length, 4); 359 | assert.ok(logs[0].message.indexOf('EINVALIDARGS, received') !== -1); 360 | assert.ok(logs[1].message.indexOf('EINVALIDARGS, alpha received') !== -1); 361 | assert.ok(logs[2].message.indexOf('EINVALIDARGS, beta received') !== -1); 362 | assert.ok(logs[3].message.indexOf('EINVALIDARGS, cell received') !== -1); 363 | 364 | return app.electron.remote.getGlobal('ipcCalls') 365 | .then(function (ipcCalls) { 366 | assert.equal(ipcCalls.length, 4); 367 | assert.equal(ipcCalls[0], 'app:hello '); 368 | assert.equal(ipcCalls[1], 'app:hello alpha'); 369 | assert.equal(ipcCalls[2], 'app:hello beta'); 370 | assert.equal(ipcCalls[3], 'app:hello cell'); 371 | }); 372 | }); 373 | }); 374 | }); 375 | 376 | describe('app-main2main-reply', function () { 377 | this.timeout(0); 378 | let app = null; 379 | 380 | before(function () { 381 | app = new Application({ 382 | path: electron, 383 | args: [path.join(__dirname, 'fixtures', 'app-main2main-reply')] 384 | }); 385 | return app.start(); 386 | }); 387 | 388 | after(function () { 389 | if (app && app.isRunning()) { 390 | return app.stop(); 391 | } 392 | }); 393 | 394 | it('should be ok', function () { 395 | return app.electron.remote.getGlobal('ipcCalls') 396 | .then(function (ipcCalls) { 397 | assert.equal(ipcCalls.length, 10); 398 | assert.equal(ipcCalls[0], 'app:hello '); 399 | assert.equal(ipcCalls[1], ' received'); 400 | assert.equal(ipcCalls[2], 'app:hello alpha'); 401 | assert.equal(ipcCalls[3], 'alpha received'); 402 | assert.equal(ipcCalls[4], 'app:hello beta'); 403 | assert.equal(ipcCalls[5], 'beta received'); 404 | assert.equal(ipcCalls[6], 'app:hello cell'); 405 | assert.equal(ipcCalls[7], 'cell received'); 406 | assert.equal(ipcCalls[8], 'app:hello foobar'); 407 | assert.equal(ipcCalls[9], 'Error: user, foobar failed'); 408 | }); 409 | }); 410 | }); 411 | -------------------------------------------------------------------------------- /test/send-to-main.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const electron = require('electron'); 5 | const {Application} = require('spectron'); 6 | const assert = require('assert'); 7 | 8 | describe('app-win2main', function () { 9 | this.timeout(0); 10 | let app = null; 11 | 12 | before(function () { 13 | app = new Application({ 14 | path: electron, 15 | args: [path.join(__dirname, 'fixtures', 'app-win2main')] 16 | }); 17 | return app.start(); 18 | }); 19 | 20 | after(function () { 21 | if (app && app.isRunning()) { 22 | return app.stop(); 23 | } 24 | }); 25 | 26 | it('should be ok', function () { 27 | return app.client 28 | .windowByIndex(0) 29 | .waitUntilWindowLoaded() 30 | .getRenderProcessLogs() 31 | .then(function (logs) { 32 | assert.equal(logs.length, 0); 33 | 34 | return app.electron.remote.getGlobal('ipcCalls') 35 | .then(function (ipcCalls) { 36 | assert.equal(ipcCalls.length, 4); 37 | assert.equal(ipcCalls[0], 'app:hello '); 38 | assert.equal(ipcCalls[1], 'app:hello alpha'); 39 | assert.equal(ipcCalls[2], 'app:hello beta'); 40 | assert.equal(ipcCalls[3], 'app:hello cell'); 41 | }); 42 | }); 43 | }); 44 | }); 45 | 46 | describe('app-main2main', function () { 47 | this.timeout(0); 48 | let app = null; 49 | 50 | before(function () { 51 | app = new Application({ 52 | path: electron, 53 | args: [path.join(__dirname, 'fixtures', 'app-main2main')] 54 | }); 55 | return app.start(); 56 | }); 57 | 58 | after(function () { 59 | if (app && app.isRunning()) { 60 | return app.stop(); 61 | } 62 | }); 63 | 64 | it('should be ok', function () { 65 | return app.electron.remote.getGlobal('ipcCalls') 66 | .then(function (ipcCalls) { 67 | assert.equal(ipcCalls.length, 4); 68 | assert.equal(ipcCalls[0], 'app:hello '); 69 | assert.equal(ipcCalls[1], 'app:hello alpha'); 70 | assert.equal(ipcCalls[2], 'app:hello beta'); 71 | assert.equal(ipcCalls[3], 'app:hello cell'); 72 | }); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /test/send-to-win-reply.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const electron = require('electron'); 5 | const {Application} = require('spectron'); 6 | const assert = require('assert'); 7 | 8 | describe('app-main2win-reply', function () { 9 | this.timeout(0); 10 | let app = null; 11 | 12 | before(function () { 13 | app = new Application({ 14 | path: electron, 15 | args: [path.join(__dirname, 'fixtures', 'app-main2win-reply')] 16 | }); 17 | return app.start(); 18 | }); 19 | 20 | after(function () { 21 | if (app && app.isRunning()) { 22 | return app.stop(); 23 | } 24 | }); 25 | 26 | it('should be ok', function () { 27 | return app.client 28 | .windowByIndex(0) 29 | .waitUntilTextExists('.label', 'Ready') 30 | .getRenderProcessLogs() 31 | .then(function (logs) { 32 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 33 | assert.ok(logs[1].message.indexOf('app:hello cell') !== -1); 34 | 35 | return app.client 36 | .windowByIndex(1) 37 | .waitUntilTextExists('.label', 'Ready') 38 | .getRenderProcessLogs() 39 | .then(function (logs) { 40 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 41 | assert.ok(logs[1].message.indexOf('app:hello beta') !== -1); 42 | 43 | return app.client 44 | .windowByIndex(2) 45 | .waitUntilTextExists('.label', 'Ready') 46 | .getRenderProcessLogs() 47 | .then(function (logs) { 48 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 49 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 50 | 51 | return app.electron.remote.getGlobal('ipcCalls') 52 | .then(function (ipcCalls) { 53 | assert.equal(ipcCalls.length, 6); 54 | assert.equal(ipcCalls[0], ' received'); 55 | assert.equal(ipcCalls[1], 'alpha received'); 56 | assert.equal(ipcCalls[2], ' received'); 57 | assert.equal(ipcCalls[3], 'beta received'); 58 | assert.equal(ipcCalls[4], ' received'); 59 | assert.equal(ipcCalls[5], 'cell received'); 60 | }); 61 | }); 62 | }); 63 | }); 64 | }); 65 | }); 66 | 67 | describe('app-main2win-reply-nested', function () { 68 | this.timeout(0); 69 | let app = null; 70 | 71 | before(function () { 72 | app = new Application({ 73 | path: electron, 74 | args: [path.join(__dirname, 'fixtures', 'app-main2win-reply-nested')] 75 | }); 76 | return app.start(); 77 | }); 78 | 79 | after(function () { 80 | if (app && app.isRunning()) { 81 | return app.stop(); 82 | } 83 | }); 84 | 85 | it('should be ok', function () { 86 | return app.client 87 | .windowByIndex(0) 88 | .waitUntilTextExists('.label', 'Ready') 89 | .getRenderProcessLogs() 90 | .then(function (logs) { 91 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 92 | assert.ok(logs[1].message.indexOf('app:hello cell') !== -1); 93 | assert.ok(logs[2].message.indexOf('app:hello-nested ') !== -1); 94 | assert.ok(logs[3].message.indexOf('app:hello-nested cell-nested') !== -1); 95 | 96 | return app.client 97 | .windowByIndex(1) 98 | .waitUntilTextExists('.label', 'Ready') 99 | .getRenderProcessLogs() 100 | .then(function (logs) { 101 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 102 | assert.ok(logs[1].message.indexOf('app:hello beta') !== -1); 103 | assert.ok(logs[2].message.indexOf('app:hello-nested ') !== -1); 104 | assert.ok(logs[3].message.indexOf('app:hello-nested beta-nested') !== -1); 105 | 106 | return app.client 107 | .windowByIndex(2) 108 | .waitUntilTextExists('.label', 'Ready') 109 | .getRenderProcessLogs() 110 | .then(function (logs) { 111 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 112 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 113 | assert.ok(logs[2].message.indexOf('app:hello-nested ') !== -1); 114 | assert.ok(logs[3].message.indexOf('app:hello-nested alpha-nested') !== -1); 115 | 116 | return app.electron.remote.getGlobal('ipcCalls') 117 | .then(function (ipcCalls) { 118 | assert.equal(ipcCalls.length, 12); 119 | assert.equal(ipcCalls[ 0], ' received'); 120 | assert.equal(ipcCalls[ 1], 'alpha received'); 121 | assert.equal(ipcCalls[ 2], ' received'); 122 | assert.equal(ipcCalls[ 3], 'alpha-nested received'); 123 | assert.equal(ipcCalls[ 4], ' received'); 124 | assert.equal(ipcCalls[ 5], 'beta received'); 125 | assert.equal(ipcCalls[ 6], ' received'); 126 | assert.equal(ipcCalls[ 7], 'beta-nested received'); 127 | assert.equal(ipcCalls[ 8], ' received'); 128 | assert.equal(ipcCalls[ 9], 'cell received'); 129 | assert.equal(ipcCalls[10], ' received'); 130 | assert.equal(ipcCalls[11], 'cell-nested received'); 131 | }); 132 | }); 133 | }); 134 | }); 135 | }); 136 | }); 137 | 138 | describe('app-main2win-reply-more-than-once', function () { 139 | this.timeout(0); 140 | let app = null; 141 | 142 | before(function () { 143 | app = new Application({ 144 | path: electron, 145 | args: [path.join(__dirname, 'fixtures', 'app-main2win-reply-more-than-once')] 146 | }); 147 | return app.start(); 148 | }); 149 | 150 | after(function () { 151 | if (app && app.isRunning()) { 152 | return app.stop(); 153 | } 154 | }); 155 | 156 | it('should be ok', function () { 157 | return app.client 158 | .windowByIndex(0) 159 | .waitUntilWindowLoaded() 160 | .getRenderProcessLogs() 161 | .then(function (logs) { 162 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 163 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 164 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 165 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 166 | 167 | return app.electron.remote.getGlobal('ipcCalls') 168 | .then(function (ipcCalls) { 169 | assert.equal(ipcCalls.length, 4); 170 | assert.equal(ipcCalls[0], ' received'); 171 | assert.equal(ipcCalls[1], 'alpha received'); 172 | assert.equal(ipcCalls[2], 'beta received'); 173 | assert.equal(ipcCalls[3], 'cell received'); 174 | }); 175 | }); 176 | }); 177 | }); 178 | 179 | describe('app-main2win-reply-timeout', function () { 180 | this.timeout(0); 181 | let app = null; 182 | 183 | before(function () { 184 | app = new Application({ 185 | path: electron, 186 | args: [path.join(__dirname, 'fixtures', 'app-main2win-reply-timeout')] 187 | }); 188 | return app.start(); 189 | }); 190 | 191 | after(function () { 192 | if (app && app.isRunning()) { 193 | return app.stop(); 194 | } 195 | }); 196 | 197 | it('should be ok', function () { 198 | return app.client 199 | .windowByIndex(0) 200 | .waitUntilTextExists('.label', 'Ready') 201 | .getRenderProcessLogs() 202 | .then(function (logs) { 203 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 204 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 205 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 206 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 207 | 208 | return app.electron.remote.getGlobal('ipcCalls') 209 | .then(function (ipcCalls) { 210 | assert.equal(ipcCalls.length, 4); 211 | assert.equal(ipcCalls[0], 'timeout'); 212 | assert.equal(ipcCalls[1], 'timeout alpha'); 213 | assert.equal(ipcCalls[2], 'timeout beta'); 214 | assert.equal(ipcCalls[3], 'cell received'); 215 | }); 216 | }); 217 | }); 218 | }); 219 | 220 | describe('app-main2win-reply-cancel-request', function () { 221 | this.timeout(0); 222 | let app = null; 223 | 224 | before(function () { 225 | app = new Application({ 226 | path: electron, 227 | args: [path.join(__dirname, 'fixtures', 'app-main2win-reply-cancel-request')] 228 | }); 229 | return app.start(); 230 | }); 231 | 232 | after(function () { 233 | if (app && app.isRunning()) { 234 | return app.stop(); 235 | } 236 | }); 237 | 238 | it('should be ok', function () { 239 | return app.client 240 | .windowByIndex(0) 241 | .waitUntilTextExists('.label', 'Ready') 242 | .getRenderProcessLogs() 243 | .then(function (logs) { 244 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 245 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 246 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 247 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 248 | 249 | return app.electron.remote.getGlobal('ipcCalls') 250 | .then(function (ipcCalls) { 251 | assert.equal(ipcCalls.length, 0); 252 | }); 253 | }); 254 | }); 255 | }); 256 | 257 | describe('app-main2win-reply-error-win-destroyed', function () { 258 | this.timeout(0); 259 | let app = null; 260 | 261 | before(function () { 262 | app = new Application({ 263 | path: electron, 264 | args: [path.join(__dirname, 'fixtures', 'app-main2win-reply-error-win-destroyed')] 265 | }); 266 | return app.start(); 267 | }); 268 | 269 | after(function () { 270 | if (app && app.isRunning()) { 271 | return app.stop(); 272 | } 273 | }); 274 | 275 | it('should be ok', function () { 276 | return app.client 277 | .windowByIndex(0) // NOTE: yes, should be index-0, not index-1 278 | .waitUntilTextExists('.label', 'Ready') 279 | .then(function () { 280 | return app.electron.remote.getGlobal('ipcCalls') 281 | .then(function (ipcCalls) { 282 | assert.equal(ipcCalls.length, 1); 283 | assert.equal(ipcCalls[0], 'EWINCLOSED, undefined'); 284 | }); 285 | }); 286 | }); 287 | }); 288 | 289 | describe('app-main2win-reply-a-user-error', function () { 290 | this.timeout(0); 291 | let app = null; 292 | 293 | before(function () { 294 | app = new Application({ 295 | path: electron, 296 | args: [path.join(__dirname, 'fixtures', 'app-main2win-reply-a-user-error')] 297 | }); 298 | return app.start(); 299 | }); 300 | 301 | after(function () { 302 | if (app && app.isRunning()) { 303 | return app.stop(); 304 | } 305 | }); 306 | 307 | it('should be ok', function () { 308 | return app.client 309 | .windowByIndex(0) 310 | .waitUntilWindowLoaded() 311 | .getRenderProcessLogs() 312 | .then(function (logs) { 313 | assert.equal(logs.length, 4); 314 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 315 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 316 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 317 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 318 | 319 | return app.electron.remote.getGlobal('ipcCalls') 320 | .then(function (ipcCalls) { 321 | assert.equal(ipcCalls.length, 4); 322 | assert.equal(ipcCalls[0], 'Error: user, failed'); 323 | assert.equal(ipcCalls[1], 'Error: user, alpha failed'); 324 | assert.equal(ipcCalls[2], 'Error: user, beta failed'); 325 | assert.equal(ipcCalls[3], 'Error: user, cell failed'); 326 | }); 327 | }); 328 | }); 329 | }); 330 | 331 | describe('app-main2win-reply-error-invalid-first-arg', function () { 332 | this.timeout(0); 333 | let app = null; 334 | 335 | before(function () { 336 | app = new Application({ 337 | path: electron, 338 | args: [path.join(__dirname, 'fixtures', 'app-main2win-reply-error-invalid-first-arg')] 339 | }); 340 | return app.start(); 341 | }); 342 | 343 | after(function () { 344 | if (app && app.isRunning()) { 345 | return app.stop(); 346 | } 347 | }); 348 | 349 | it('should be ok', function () { 350 | return app.client 351 | .windowByIndex(0) 352 | .waitUntilWindowLoaded() 353 | .getRenderProcessLogs() 354 | .then(function (logs) { 355 | assert.equal(logs.length, 8); 356 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 357 | assert.ok(logs[1].message.indexOf('Invalid argument for event.reply') !== -1); 358 | assert.ok(logs[2].message.indexOf('app:hello alpha') !== -1); 359 | assert.ok(logs[3].message.indexOf('Invalid argument for event.reply') !== -1); 360 | assert.ok(logs[4].message.indexOf('app:hello beta') !== -1); 361 | assert.ok(logs[5].message.indexOf('Invalid argument for event.reply') !== -1); 362 | assert.ok(logs[6].message.indexOf('app:hello cell') !== -1); 363 | assert.ok(logs[7].message.indexOf('Invalid argument for event.reply') !== -1); 364 | 365 | return app.electron.remote.getGlobal('ipcCalls') 366 | .then(function (ipcCalls) { 367 | assert.equal(ipcCalls.length, 4); 368 | assert.equal(ipcCalls[0], 'EINVALIDARGS, received'); 369 | assert.equal(ipcCalls[1], 'EINVALIDARGS, alpha received'); 370 | assert.equal(ipcCalls[2], 'EINVALIDARGS, beta received'); 371 | assert.equal(ipcCalls[3], 'EINVALIDARGS, cell received'); 372 | }); 373 | }); 374 | }); 375 | }); 376 | -------------------------------------------------------------------------------- /test/send-to-win.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const electron = require('electron'); 5 | const {Application} = require('spectron'); 6 | const assert = require('assert'); 7 | 8 | describe('app-main2win', function () { 9 | this.timeout(0); 10 | let app = null; 11 | 12 | before(function () { 13 | app = new Application({ 14 | path: electron, 15 | args: [path.join(__dirname, 'fixtures', 'app-main2win')] 16 | }); 17 | return app.start(); 18 | }); 19 | 20 | after(function () { 21 | if (app && app.isRunning()) { 22 | return app.stop(); 23 | } 24 | }); 25 | 26 | it('should be ok', function () { 27 | return app.client 28 | .windowByIndex(0) 29 | .waitUntilWindowLoaded() 30 | .getRenderProcessLogs() 31 | .then(function (logs) { 32 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 33 | assert.ok(logs[1].message.indexOf('app:hello cell') !== -1); 34 | 35 | return app.client 36 | .windowByIndex(1) 37 | .waitUntilWindowLoaded() 38 | .getRenderProcessLogs() 39 | .then(function (logs) { 40 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 41 | assert.ok(logs[1].message.indexOf('app:hello beta') !== -1); 42 | 43 | return app.client 44 | .windowByIndex(2) 45 | .waitUntilWindowLoaded() 46 | .getRenderProcessLogs() 47 | .then(function (logs) { 48 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 49 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 50 | 51 | return app.electron.remote.getGlobal('ipcCalls') 52 | .then(function (ipcCalls) { 53 | assert.equal(ipcCalls.length, 0); 54 | }); 55 | }); 56 | }); 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /test/send-to-wins.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const electron = require('electron'); 5 | const {Application} = require('spectron'); 6 | const assert = require('assert'); 7 | 8 | describe('app-main2wins', function () { 9 | this.timeout(0); 10 | let app = null; 11 | 12 | before(function () { 13 | app = new Application({ 14 | path: electron, 15 | args: [path.join(__dirname, 'fixtures', 'app-main2wins')] 16 | }); 17 | return app.start(); 18 | }); 19 | 20 | after(function () { 21 | if (app && app.isRunning()) { 22 | return app.stop(); 23 | } 24 | }); 25 | 26 | it('should be ok', function () { 27 | return app.client 28 | .windowByIndex(0) 29 | .waitUntilWindowLoaded() 30 | .getRenderProcessLogs() 31 | .then(function (logs) { 32 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 33 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 34 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 35 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 36 | 37 | return app.client 38 | .windowByIndex(1) 39 | .waitUntilWindowLoaded() 40 | .getRenderProcessLogs() 41 | .then(function (logs) { 42 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 43 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 44 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 45 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 46 | 47 | return app.client 48 | .windowByIndex(2) 49 | .waitUntilWindowLoaded() 50 | .getRenderProcessLogs() 51 | .then(function (logs) { 52 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 53 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 54 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 55 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 56 | 57 | return app.electron.remote.getGlobal('ipcCalls') 58 | .then(function (ipcCalls) { 59 | assert.equal(ipcCalls.length, 0); 60 | }); 61 | }); 62 | }); 63 | }); 64 | }); 65 | }); 66 | 67 | describe('app-win2wins', function () { 68 | this.timeout(0); 69 | let app = null; 70 | 71 | before(function () { 72 | app = new Application({ 73 | path: electron, 74 | args: [path.join(__dirname, 'fixtures', 'app-win2wins')] 75 | }); 76 | return app.start(); 77 | }); 78 | 79 | after(function () { 80 | if (app && app.isRunning()) { 81 | return app.stop(); 82 | } 83 | }); 84 | 85 | it('should be ok', function () { 86 | return app.client 87 | .windowByIndex(0) 88 | .waitUntilWindowLoaded() 89 | .getRenderProcessLogs() 90 | .then(function (logs) { 91 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 92 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 93 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 94 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 95 | 96 | return app.client 97 | .windowByIndex(1) 98 | .waitUntilWindowLoaded() 99 | .getRenderProcessLogs() 100 | .then(function (logs) { 101 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 102 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 103 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 104 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 105 | 106 | return app.client 107 | .windowByIndex(2) 108 | .waitUntilWindowLoaded() 109 | .getRenderProcessLogs() 110 | .then(function (logs) { 111 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 112 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 113 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 114 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 115 | 116 | return app.electron.remote.getGlobal('ipcCalls') 117 | .then(function (ipcCalls) { 118 | assert.equal(ipcCalls.length, 0); 119 | }); 120 | }); 121 | }); 122 | }); 123 | }); 124 | }); 125 | 126 | 127 | describe('app-win2wins-exclude-self', function () { 128 | this.timeout(0); 129 | let app = null; 130 | 131 | before(function () { 132 | app = new Application({ 133 | path: electron, 134 | args: [path.join(__dirname, 'fixtures', 'app-win2wins-exclude-self')] 135 | }); 136 | return app.start(); 137 | }); 138 | 139 | after(function () { 140 | if (app && app.isRunning()) { 141 | return app.stop(); 142 | } 143 | }); 144 | 145 | it('should be ok', function () { 146 | return app.client 147 | .windowByIndex(0) 148 | .waitUntilWindowLoaded() 149 | .getRenderProcessLogs() 150 | .then(function (logs) { 151 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 152 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 153 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 154 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 155 | 156 | return app.client 157 | .windowByIndex(1) 158 | .waitUntilWindowLoaded() 159 | .getRenderProcessLogs() 160 | .then(function (logs) { 161 | assert.ok(logs[0].message.indexOf('app:hello ') !== -1); 162 | assert.ok(logs[1].message.indexOf('app:hello alpha') !== -1); 163 | assert.ok(logs[2].message.indexOf('app:hello beta') !== -1); 164 | assert.ok(logs[3].message.indexOf('app:hello cell') !== -1); 165 | 166 | return app.client 167 | .windowByIndex(2) 168 | .waitUntilWindowLoaded() 169 | .getRenderProcessLogs() 170 | .then(function (logs) { 171 | assert.equal(logs.length, 0); 172 | 173 | return app.electron.remote.getGlobal('ipcCalls') 174 | .then(function (ipcCalls) { 175 | assert.equal(ipcCalls.length, 0); 176 | }); 177 | }); 178 | }); 179 | }); 180 | }); 181 | }); 182 | --------------------------------------------------------------------------------