Electron App End-to-end Testing with Jest and Spectron
Electron app is a hybrid of both native and web world. Thus we have both nodejs part and web part. That explain the size of the app and memory consumption depending on the nature of your app. I manage to get one running and only consume about ~60MB memory which cool for an electron app (But can't be compare with native app obviously)
I this article we are going to take a look at basic UI test for electron app. UI test for Electron or Integration Test or whatever test you want to call it, can be done using the hardway which probably usig puppeteer and i don't know how. But the easy way is to use Spectron. For obvious reason you can choose whatever flavor of the test framework like in the offical docs which is using Mocha. However in this example we are gonna use Jest with vanilla javascript.
Spectron covered everything that we need and make it easier for us.
If you have question or feedback, don't hesitate to tweet me on twitter.
Getting Started
Before we can do any test, we first have to make sure we have the tools installed. Here are the steps that we take to make sure all tools are ready.
- Electron
- Jest
- Spectron
-
First clone or download the repo for the demo electron app i created here. Navigate to the project folder then run
npm install
, this will install electron. So we got our first requirement covered. You can use also use your own eletron app. -
Install Jest and Spectron as dev dependencies, include @types-jest if you want vscode intellisense for jest.
npm install -D spectron jest @types/jest
Basic Test
Now that we have the tools, let's see how the basic test look like. The function are all asyncronous and should be treated as one or will give us undefined
most of the time as our test code are syncronous.
Following the example on spectron offical bhomepage, it shows an example using promises
with then
and catch
However ccording to jest documentation, we can also use either return
or await
for asyncronous function. Most electron function are asyncronous by nature.
I prefer to use async/await than using promises then and catch. It much cleaner and easier for me to read. Plus i don't have to deal with callbacks.
In this test, we first have to add the timeout or the test will run before the app even load the window. I use 10000ms on my mac and it seems to work but on my low end laptop i have to increase it to 50000ms for the test to work since it took longer to start the app.
Then we set start the app before the test run and make sure to clean up and close the app when all test has been ran.
In this basic test we only check if the window is visible and then check the window count. With this UI test as a starting point you can run along with all your other test file, simply using the jest
command or jest --coverage
const path = require('path');
const Application = require('spectron').Application;
const electron = require('electron');
jest.setTimeout(10000); // increase to 50000 on low spec laptop
let app = null;
beforeAll(function () {
app = new Application({
path: electron,
args: [path.join(__dirname, '..', 'src', 'js', 'main.js')]
});
return app.start();
});
afterAll(function() {
if (app && app.isRunning()) {
return app.stop();
}
});
test('App Init', async function() {
let isVisible = await app.browserWindow.isVisible();
expect(isVisible).toBe(true);
let count = await app.client.getWindowCount();
expect(count).toEqual(1);
});
References
- https://jestjs.io/docs/en/setup-teardown
- https://jestjs.io/docs/en/asynchronous
- https://www.electronjs.org/spectron
- https://gulpjs.com/docs/en/getting-started/async-completion