I have an electron application that first starts a launcher window (in a renderer process) that starts several background services. After those background services started successfully it sends "services-running"
on its ipcRenderer
back to the main process which in turn reacts to that event by closing the launcher window and starting the main application window. The event is of course received by ipcMain.on('services-running',...)
I unit tested all the handlers separately so those are fine and now I want to integration test the events that pass through ipcMain
.
This is how my integration test looks at the moment:
import { Application } from 'spectron';
import * as electron from "electron";
import { expect } from 'chai';
import * as chai from 'chai';
import * as chaiAsPromised from 'chai-as-promised';
let app: Application;
global.before(() => {
app = new Application({
path: "" + electron,
args: ["app/main.js"],
env: {
ELECTRON_ENABLE_LOGGING: true,
ELECTRON_ENABLE_STACK_DUMPING: true,
NODE_ENV: "integrationtest"
},
startTimeout: 20000,
chromeDriverLogPath: '../chromedriverlog.txt'
});
chai.use(chaiAsPromised);
chai.should();
});
describe('Application', () => {
before('Start Application', () => {
return app.start();
});
after(() => {
if(app && app.isRunning()){
return app.stop();
}
});
it('should start the launcher', async () => {
await app.client.waitUntilWindowLoaded();
return app.client.getTitle().should.eventually.equal('Launcher');
});
it('should start all services before timing out', async (done) => {
console.log('subscribed');
app.electron.remote.ipcMain.on('services-running', () => {
done();
});
});
});
The first test works fine. The second test will fail eventually after the timeout is reached although I can see subscribed
on the shell before the main window pops up, so the event is definitely fired.
I read in the documentation that nodeIntegration
needs to be enabled to access the full electron api with spectron, all my renderer processes are started with {nodeIntegration: true}
in their respective webPreferences
. But since I am interested in the main process I think this does not apply (or at least I think it shouldn't since the main process is a node process per se).
So my main question is, how would I bind to ipcMain
events and include those in my assertions. Also how would I know when the launcher window is closed and the "main" window has been opened?
As a bonus I have some understanding issues with the spectron api.
If I look at the
spectron.d.ts
theelectron
property of theApplication
is of typeElectron.AllElectron
which in turn is aMainInterface
and directly has theipcMain
property. So in my understanding accessingipcMain
should beapp.electron.ipcMain
(which is undefined), where is that remote coming from and why is it invisible in thespectron.d.ts
.The methods on
SpectronClient
all returnPromise<void>
. So I have toawait
orthen
those. If I look at the javascript examples they chain the client statements:
return app.client
.waitUntilWindowLoaded()
.getTitle().should.equal('Launcher');
This doesn't work in typescript because you can't chain to a Promise<void>
obviously,... how does that work to in js?